/**
 * Booking ORM Mapper
 *
 * Maps between Booking domain entity and BookingOrmEntity
 */

import { Booking, BookingProps, Party, BookingContainer } from '@domain/entities/booking.entity';
import { BookingNumber } from '@domain/value-objects/booking-number.vo';
import { BookingStatus } from '@domain/value-objects/booking-status.vo';
import { BookingOrmEntity, PartyJson } from '../entities/booking.orm-entity';
import { ContainerOrmEntity } from '../entities/container.orm-entity';

export class BookingOrmMapper {
  /**
   * Map domain entity to ORM entity
   */
  static toOrm(domain: Booking): BookingOrmEntity {
    const orm = new BookingOrmEntity();

    orm.id = domain.id;
    orm.bookingNumber = domain.bookingNumber.value;
    orm.userId = domain.userId;
    orm.organizationId = domain.organizationId;
    orm.rateQuoteId = domain.rateQuoteId;
    orm.status = domain.status.value;
    orm.shipper = this.partyToJson(domain.shipper);
    orm.consignee = this.partyToJson(domain.consignee);
    orm.cargoDescription = domain.cargoDescription;
    orm.specialInstructions = domain.specialInstructions || null;
    orm.commissionRate = domain.commissionRate ?? null;
    orm.commissionAmountEur = domain.commissionAmountEur ?? null;
    orm.createdAt = domain.createdAt;
    orm.updatedAt = domain.updatedAt;

    // Map containers
    orm.containers = domain.containers.map(container => this.containerToOrm(container, domain.id));

    return orm;
  }

  /**
   * Map ORM entity to domain entity
   */
  static toDomain(orm: BookingOrmEntity): Booking {
    const props: BookingProps = {
      id: orm.id,
      bookingNumber: BookingNumber.fromString(orm.bookingNumber),
      userId: orm.userId,
      organizationId: orm.organizationId,
      rateQuoteId: orm.rateQuoteId,
      status: BookingStatus.create(orm.status as any),
      shipper: this.jsonToParty(orm.shipper),
      consignee: this.jsonToParty(orm.consignee),
      cargoDescription: orm.cargoDescription,
      containers: orm.containers ? orm.containers.map(c => this.ormToContainer(c)) : [],
      specialInstructions: orm.specialInstructions || undefined,
      commissionRate: orm.commissionRate != null ? Number(orm.commissionRate) : undefined,
      commissionAmountEur:
        orm.commissionAmountEur != null ? Number(orm.commissionAmountEur) : undefined,
      createdAt: orm.createdAt,
      updatedAt: orm.updatedAt,
    };

    return Booking.create({
      ...props,
      bookingNumber: props.bookingNumber,
      status: props.status,
    });
  }

  /**
   * Map array of ORM entities to domain entities
   */
  static toDomainMany(orms: BookingOrmEntity[]): Booking[] {
    return orms.map(orm => this.toDomain(orm));
  }

  /**
   * Convert domain Party to JSON
   */
  private static partyToJson(party: Party): PartyJson {
    return {
      name: party.name,
      address: {
        street: party.address.street,
        city: party.address.city,
        postalCode: party.address.postalCode,
        country: party.address.country,
      },
      contactName: party.contactName,
      contactEmail: party.contactEmail,
      contactPhone: party.contactPhone,
    };
  }

  /**
   * Convert JSON to domain Party
   */
  private static jsonToParty(json: PartyJson): Party {
    return {
      name: json.name,
      address: {
        street: json.address.street,
        city: json.address.city,
        postalCode: json.address.postalCode,
        country: json.address.country,
      },
      contactName: json.contactName,
      contactEmail: json.contactEmail,
      contactPhone: json.contactPhone,
    };
  }

  /**
   * Convert domain BookingContainer to ORM entity
   */
  private static containerToOrm(
    container: BookingContainer,
    bookingId: string
  ): ContainerOrmEntity {
    const orm = new ContainerOrmEntity();
    orm.id = container.id;
    orm.bookingId = bookingId;
    orm.type = container.type;
    orm.containerNumber = container.containerNumber || null;
    orm.vgm = container.vgm || null;
    orm.temperature = container.temperature || null;
    orm.sealNumber = container.sealNumber || null;
    return orm;
  }

  /**
   * Convert ORM entity to domain BookingContainer
   */
  private static ormToContainer(orm: ContainerOrmEntity): BookingContainer {
    return {
      id: orm.id,
      type: orm.type,
      containerNumber: orm.containerNumber || undefined,
      vgm: orm.vgm || undefined,
      temperature: orm.temperature || undefined,
      sealNumber: orm.sealNumber || undefined,
    };
  }
}
