import { BadRequestException } from '@nestjs/common';

import { Contract } from './entities/contract.entity';
import { INTERCITY_DOCUMENTS_SETTING_CODE } from '../bookings/clearance.util';

/**
 * Resolves which seeded clearance FileUploadSetting applies to a contract during
 * the CONTRACT pre-booking phase (Path B). Mirrors clearance.util.ts but emits
 * `contract_clearance_*` codes keyed on (tradeDirection, freightType, customs).
 */

type Op = 'import' | 'export';
type Freight = 'container' | 'bulk';

/** Trade direction → clearance operation. DOMESTIC has no customs clearance. */
function operationFor(tradeDirection: string): Op | null {
  if (tradeDirection === 'IMPORT') return 'import';
  if (tradeDirection === 'EXPORT') return 'export';
  return null; // DOMESTIC / intercity — no clearance gate
}

function freightFor(freightType: string): Freight {
  return freightType === 'BULK' ? 'bulk' : 'container';
}

/**
 * The customer-input clearance setting code, or null when no gate applies.
 *
 * - Path B (customs bundled): the customer uploads the documents GL needs to do
 *   the clearance work → `contract_clearance_{op}_{freight}`.
 * - Path A (no customs): the customer clears the cargo himself and uploads his
 *   own (smaller) clearance proof set → `contract_clearance_selfclear_{op}_{freight}`,
 *   reviewed by Operations rather than GL.
 *
 * DOMESTIC/intercity has no border, but a ONE_TIME intercity contract still
 * collects the admin-configured intercity document set after both signatures
 * (ops-reviewed, like Path A). GENERAL intercity contracts skip the contract
 * gate and collect the same set per booking instead.
 */
export function contractClearanceSettingCode(
  tradeDirection: string,
  freightType: string,
  includesCustoms: boolean,
): string | null {
  if (tradeDirection === 'DOMESTIC') return INTERCITY_DOCUMENTS_SETTING_CODE;
  const op = operationFor(tradeDirection);
  if (!op) return null;
  const freight = freightFor(freightType);
  if (!includesCustoms) {
    return `contract_clearance_selfclear_${op}_${freight}`;
  }
  return `contract_clearance_${op}_${freight}`;
}

/** The GL-output (customs output) setting code, keyed on op + freight. */
export function contractClearanceOutputSettingCode(
  tradeDirection: string,
  freightType: string,
  includesCustoms: boolean,
): string | null {
  if (!includesCustoms) return null;
  const op = operationFor(tradeDirection);
  if (!op) return null;
  const freight = freightFor(freightType);
  return `contract_clearance_output_${op}_${freight}`;
}

/** Convenience: resolve both codes for a loaded contract. */
export function contractClearanceCodes(contract: Contract): {
  inputCode: string | null;
  outputCode: string | null;
  includesCustoms: boolean;
} {
  const includesCustoms = contract.customsClearingEnabled ?? false;
  return {
    inputCode: contractClearanceSettingCode(
      contract.tradeDirection,
      contract.freightType,
      includesCustoms,
    ),
    outputCode: contractClearanceOutputSettingCode(
      contract.tradeDirection,
      contract.freightType,
      includesCustoms,
    ),
    includesCustoms,
  };
}

/**
 * Djibouti GL cannot record a Delivery Order without saying WHEN the vessel
 * arrived and WHEN the DO was collected — the file alone leaves the import
 * timeline unauditable. Shared by the contract and per-booking DO uploads so
 * one endpoint can never be laxer than the other.
 *
 * Returns the normalized `YYYY-MM-DD` pair; throws if either is missing,
 * unparseable, or the DO predates the vessel's arrival.
 */
export function assertDoCollectionDates(dates?: {
  vesselArrivalDate?: string;
  doCollectedDate?: string;
}): { vesselArrivalDate: string; doCollectedDate: string } {
  const vesselArrivalDate = normalizeDoDate(
    dates?.vesselArrivalDate,
    'Vessel arrival date',
  );
  const doCollectedDate = normalizeDoDate(
    dates?.doCollectedDate,
    'DO collected date',
  );

  if (doCollectedDate < vesselArrivalDate) {
    throw new BadRequestException(
      'DO collected date cannot be earlier than the vessel arrival date.',
    );
  }

  return { vesselArrivalDate, doCollectedDate };
}

/** `YYYY-MM-DD` or throw — the column is a DATE, so time zones never enter. */
function normalizeDoDate(value: string | undefined, label: string): string {
  const trimmed = value?.trim();
  if (!trimmed) {
    throw new BadRequestException(`${label} is required to upload a Delivery Order.`);
  }
  const date = trimmed.slice(0, 10);
  if (!/^\d{4}-\d{2}-\d{2}$/.test(date) || Number.isNaN(Date.parse(date))) {
    throw new BadRequestException(`${label} is not a valid date.`);
  }
  return date;
}
