import { Injectable, Logger } from "@nestjs/common";
import { DataSource } from "typeorm";

import { FileUploadSetting } from "../modules/file-upload-settings/entities/file-upload-setting.entity";

interface OnboardingField {
  fileKey: string;
  fileLabel: string;
  helpText: string;
  isRequired: boolean;
  isMultiple: boolean;
  maxFiles: number;
  allowedExtensions: string[];
  maxSizeMb: number;
  displayOrder: number;
}

const DOC_EXTENSIONS = ["pdf", "jpg", "jpeg", "png"];

/** fileKey of the delegation letter attached to the Power of Attorney step. */
export const POA_DELEGATION_FILE_KEY = "poa_delegation_letter";

/**
 * Seeded as optional: the delegation letter is only mandatory once a PoA has
 * been entered, or when the company operates as a freight forwarder. That rule
 * spans form fields as well as files, so it lives in the onboarding gate
 * (companies.service.getOnboardingRequirements) rather than in `isRequired`.
 */
const poaDelegationField = (displayOrder: number): OnboardingField => ({
  fileKey: POA_DELEGATION_FILE_KEY,
  fileLabel: "PoA Delegation Letter",
  helpText:
    "Signed letter in which the General Manager delegates the representative named above.",
  isRequired: false,
  isMultiple: false,
  maxFiles: 1,
  allowedExtensions: DOC_EXTENSIONS,
  maxSizeMb: 10,
  displayOrder,
});

/** Documents required from an Ethiopian company at onboarding. */
const ETHIOPIAN_ONBOARDING_FIELDS: OnboardingField[] = [
  {
    fileKey: "tin_certificate",
    fileLabel: "TIN Certificate",
    helpText: "Verified against the TIN registry during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 1,
  },
  {
    fileKey: "commercial_license",
    fileLabel: "Commercial Registration",
    helpText:
      "Verified against the government trade system during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 2,
  },
  {
    fileKey: "national_id",
    fileLabel: "National ID",
    helpText: "Verified against the National ID API during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 3,
  },
  poaDelegationField(4),
];

/** Documents required from a Foreign company at onboarding. */
const FOREIGN_ONBOARDING_FIELDS: OnboardingField[] = [
  {
    fileKey: "tin_certificate",
    fileLabel: "TIN Certificate",
    helpText: "Verified against the TIN registry during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 1,
  },
  {
    fileKey: "investment_license",
    fileLabel: "Investment License",
    helpText: "Investment license issued for operating in Ethiopia.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 2,
  },
  {
    fileKey: "national_id",
    fileLabel: "National ID",
    helpText: "National ID of the company's authorized representative.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 3,
  },
  {
    fileKey: "passport",
    fileLabel: "Passport",
    helpText: "Passport of the company's authorized representative.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 4,
  },
  poaDelegationField(5),
];

/** Legacy combined set, kept for the older per-company-type codes. */
const LEGACY_ONBOARDING_FIELDS: OnboardingField[] = [
  {
    fileKey: "business_license",
    fileLabel: "Business License / Trade License",
    helpText:
      "Verified against the government trade system during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 1,
  },
  {
    fileKey: "tin_certificate",
    fileLabel: "TIN Certificate",
    helpText: "Verified against the TIN registry during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 2,
  },
  {
    fileKey: "national_id_passport",
    fileLabel: "National ID / Passport",
    helpText: "Verified against the National ID API during registration.",
    isRequired: true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder: 3,
  },
];

interface OnboardingDocumentSetting {
  code: string;
  label: string;
  entity: string;
  fields: OnboardingField[];
}

const COMPANY_ONBOARDING_DOCUMENTS: OnboardingDocumentSetting[] = [
  // Nationality-based sets — the document requirements depend only on whether
  // the company is Ethiopian or Foreign (same for importer/exporter/forwarder).
  {
    code: "company_onboarding_documents_ethiopian",
    label: "Ethiopian company onboarding documents",
    entity: "customer",
    fields: ETHIOPIAN_ONBOARDING_FIELDS,
  },
  {
    code: "company_onboarding_documents_foreign",
    label: "Foreign company onboarding documents",
    entity: "customer",
    fields: FOREIGN_ONBOARDING_FIELDS,
  },
  // Legacy per-company-type codes (kept for back-compat; no longer used by the portal).
  {
    code: "company_onboarding_documents_customer",
    label: "Customer onboarding documents",
    entity: "customer",
    fields: LEGACY_ONBOARDING_FIELDS,
  },
  {
    code: "company_onboarding_documents_forwarder",
    label: "Forwarder onboarding documents",
    entity: "other",
    fields: LEGACY_ONBOARDING_FIELDS,
  },
  {
    code: "company_onboarding_documents_transporter",
    label: "Transporter onboarding documents",
    entity: "other",
    fields: LEGACY_ONBOARDING_FIELDS,
  },
  {
    code: "company_onboarding_documents_forwarder_dj",
    label: "Djibouti forwarder onboarding documents",
    entity: "other",
    fields: LEGACY_ONBOARDING_FIELDS,
  },
];

const COMPANY_ONBOARDING_DESCRIPTION =
  "Required documents for external company onboarding, by company nationality.";

// ── Clearance document settings ────────────────────────────────────────────
// Operation/clearance documents collected after contract counter-sign, resolved
// at runtime from (operationType, freightType, includesCustoms). The `entity`
// is "booking_clearance" so the backoffice file-settings editor can filter them.
// Two kinds of set per customs category: a CUSTOMER-INPUT set (the customer
// uploads) and a GL-OUTPUT set (Global Logistics uploads the customs outputs).

const JPG_EXTENSIONS = ["jpg", "jpeg", "png", "pdf"];
const CLEARANCE_ENTITY = "booking_clearance";

/** Build a clearance field with sensible defaults; `critical` marks isRequired. */
function clearanceField(
  fileKey: string,
  fileLabel: string,
  displayOrder: number,
  opts?: { required?: boolean; help?: string; extensions?: string[] },
): OnboardingField {
  return {
    fileKey,
    fileLabel,
    helpText: opts?.help ?? "",
    isRequired: opts?.required ?? true,
    isMultiple: false,
    maxFiles: 1,
    allowedExtensions: opts?.extensions ?? DOC_EXTENSIONS,
    maxSizeMb: 10,
    displayOrder,
  };
}

/** Documents shared by every container import category (with/without customs). */
const IMPORT_CONTAINER_FIELDS: OnboardingField[] = [
  clearanceField("commercial_invoice", "Commercial Invoice", 1),
  clearanceField("packing_list", "Packing List", 2),
  clearanceField("import_license", "Import License", 3),
  clearanceField("certificate_of_origin", "Certificate of Origin", 4),
  clearanceField(
    "external_freight_cost",
    "External Freight Cost / Checkup Documentation",
    5,
  ),
  clearanceField("bill_of_lading", "Bill of Lading / Railway Bill", 6),
  clearanceField("vgm", "Verified Gross Mass (VGM)", 7, { required: true }),
  clearanceField("release_order", "Release Order", 8, { required: true }),
];

/** Documents shared by every container export category (with/without customs). */
const EXPORT_CONTAINER_FIELDS: OnboardingField[] = [
  clearanceField("booking_confirmation", "Booking Confirmation", 1),
  clearanceField("commercial_invoice", "Commercial Invoice", 2),
  clearanceField("packing_list", "Packing List", 3),
  clearanceField("shipping_instruction", "Shipping Instruction", 4),
  clearanceField("bank_permit", "Bank Permit", 5),
  clearanceField("export_license", "Export License", 6),
  clearanceField("vgm_letter", "VGM Letter", 7, { required: true }),
  clearanceField("railway_bill", "Railway Bill", 8),
  clearanceField("delegation_letter", "Delegation Letter / POA", 9, {
    required: false,
    help: "Required only if EDR manages all transit activity.",
  }),
];

/** Bulk import documents (shorter, transit-focused set). */
const IMPORT_BULK_FIELDS: OnboardingField[] = [
  clearanceField("packing_list", "Packing List", 1, { required: true }),
  clearanceField("bill_of_loading", "Bill of Loading", 2, { required: true }),
  clearanceField("port_invoice", "Port Invoice", 3),
];

/** Bulk export documents (transit/customs corridor docs). */
const EXPORT_BULK_FIELDS: OnboardingField[] = [
  clearanceField("release_order_djibouti", "Release Order (Djibouti)", 1),
  clearanceField("port_gate_pass", "Port Gate Pass", 2),
  clearanceField("port_invoice", "Port Invoice", 3),
];

/** GL-uploaded customs output documents (import container). */
const IMPORT_CONTAINER_OUTPUT_FIELDS: OnboardingField[] = [
  clearanceField("im4", "IM4 — Permanent Import Document", 1),
  clearanceField("im5", "IM5 — Temporary Import Document", 2, {
    required: false,
  }),
  clearanceField("transit_permitted", "Transit Permitted Screenshot", 3, {
    extensions: JPG_EXTENSIONS,
  }),
];

/** GL-uploaded customs output documents (export container). */
const EXPORT_CONTAINER_OUTPUT_FIELDS: OnboardingField[] = [
  clearanceField("ex3", "EX3 — Permanent Export Document", 1),
  clearanceField("ex8", "EX8 — Export Transit Document", 2),
  clearanceField("export_release", "Export Release", 3),
  clearanceField("t1", "T1 — Transport Document", 4),
];

const CLEARANCE_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
  // ── Customer-input sets ──
  {
    code: "clearance_import_container_with_customs",
    label: "Import container clearance documents (with customs)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_FIELDS,
  },
  {
    code: "clearance_import_container_without_customs",
    label: "Import container documents (without customs)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_FIELDS,
  },
  {
    code: "clearance_export_container_with_customs",
    label: "Export container clearance documents (with customs)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_FIELDS,
  },
  {
    code: "clearance_export_container_without_customs",
    label: "Export container documents (without customs)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_FIELDS,
  },
  {
    code: "clearance_import_bulk_with_customs",
    label: "Import bulk clearance documents (with customs)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_BULK_FIELDS,
  },
  {
    code: "clearance_import_bulk_without_customs",
    label: "Import bulk documents (without customs)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_BULK_FIELDS,
  },
  {
    code: "clearance_export_bulk_with_customs",
    label: "Export bulk clearance documents (with customs)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_BULK_FIELDS,
  },
  {
    code: "clearance_export_bulk_without_customs",
    label: "Export bulk documents (without customs)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_BULK_FIELDS,
  },
  // ── GL-output sets (customs only) ──
  {
    code: "clearance_output_import_container",
    label: "Customs output documents (import container)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_OUTPUT_FIELDS,
  },
  {
    code: "clearance_output_export_container",
    label: "Customs output documents (export container)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_OUTPUT_FIELDS,
  },
  // Bulk output sets mirror the container output docs so customs+bulk bookings
  // can finalize (previously bulk had no output set and got stuck at finalize).
  {
    code: "clearance_output_import_bulk",
    label: "Customs output documents (import bulk)",
    entity: CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_OUTPUT_FIELDS,
  },
  {
    code: "clearance_output_export_bulk",
    label: "Customs output documents (export bulk)",
    entity: CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_OUTPUT_FIELDS,
  },
];

// ── Contract pre-booking clearance settings (Path B) ────────────────────────
// For customs-clearance contracts the customer uploads clearance documents on
// the CONTRACT (before any booking exists). Same customer doc sets as the legacy
// booking clearance, plus the GL output sets, keyed on the contract. Resolved by
// contract-clearance.util.ts (codes: contract_clearance_{op}_{freight} and
// contract_clearance_output_{op}_container).
const CONTRACT_CLEARANCE_ENTITY = "contract_clearance";

const CONTRACT_CLEARANCE_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "contract_clearance_import_container",
    label: "Contract clearance documents (import container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_FIELDS,
  },
  {
    code: "contract_clearance_export_container",
    label: "Contract clearance documents (export container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_FIELDS,
  },
  {
    code: "contract_clearance_import_bulk",
    label: "Contract clearance documents (import bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: IMPORT_BULK_FIELDS,
  },
  {
    code: "contract_clearance_export_bulk",
    label: "Contract clearance documents (export bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: EXPORT_BULK_FIELDS,
  },
  // GL ET output sets uploaded during pre-booking clearance.
  {
    code: "contract_clearance_output_import_container",
    label: "Contract customs output documents (import container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_OUTPUT_FIELDS,
  },
  {
    code: "contract_clearance_output_export_container",
    label: "Contract customs output documents (export container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_OUTPUT_FIELDS,
  },
  // Bulk output sets mirror the container output docs so customs+bulk contracts
  // can finalize (previously bulk had no output set and got stuck at finalize).
  {
    code: "contract_clearance_output_import_bulk",
    label: "Contract customs output documents (import bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: IMPORT_CONTAINER_OUTPUT_FIELDS,
  },
  {
    code: "contract_clearance_output_export_bulk",
    label: "Contract customs output documents (export bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: EXPORT_CONTAINER_OUTPUT_FIELDS,
  },
];

// ── Path A self-clearance settings (no EDR customs service) ──────────────────
// When the contract does NOT bundle customs clearance, the customer clears the
// cargo himself and uploads his OWN clearance proof on the contract. Operations
// (not GL) reviews this smaller set before the customer may create the booking.
// Resolved by contract-clearance.util.ts as contract_clearance_selfclear_{op}_{freight}.
const SELF_CLEARANCE_IMPORT_FIELDS: OnboardingField[] = [
  clearanceField("customs_declaration", "Customs Declaration (IM4/IM5)", 1),
  clearanceField("import_release", "Import Release Permit", 2),
  clearanceField("duty_tax_receipt", "Duty & Tax Payment Receipt", 3, {
    required: false,
  }),
  clearanceField("delivery_order", "Delivery Order", 4, { required: false }),
  clearanceField("supporting_document", "Other Clearance Document", 5, {
    required: false,
  }),
];

const SELF_CLEARANCE_EXPORT_FIELDS: OnboardingField[] = [
  clearanceField("customs_declaration", "Customs Declaration (EX3/EX8)", 1),
  clearanceField("export_release", "Export Release", 2),
  clearanceField("transit_document", "Transit Document (T1)", 3, {
    required: false,
  }),
  clearanceField("supporting_document", "Other Clearance Document", 4, {
    required: false,
  }),
];

const SELF_CLEARANCE_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "contract_clearance_selfclear_import_container",
    label: "Self-clearance documents (import container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: SELF_CLEARANCE_IMPORT_FIELDS,
  },
  {
    code: "contract_clearance_selfclear_export_container",
    label: "Self-clearance documents (export container)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: SELF_CLEARANCE_EXPORT_FIELDS,
  },
  {
    code: "contract_clearance_selfclear_import_bulk",
    label: "Self-clearance documents (import bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: SELF_CLEARANCE_IMPORT_FIELDS,
  },
  {
    code: "contract_clearance_selfclear_export_bulk",
    label: "Self-clearance documents (export bulk)",
    entity: CONTRACT_CLEARANCE_ENTITY,
    fields: SELF_CLEARANCE_EXPORT_FIELDS,
  },
];

// ── Contract intake settings ────────────────────────────────────────────────
// Commercial/framework documents attached at contract submission (wizard step 5),
// distinct from the post-sign clearance docs above.
const CONTRACT_INTAKE_ENTITY = "contract_intake";

const CONTRACT_INTAKE_FIELDS: OnboardingField[] = [
  clearanceField(
    "commercial_framework",
    "Commercial Framework / Agreement",
    1,
    {
      required: false,
    },
  ),
  clearanceField("onboarding_attachment", "Onboarding Attachment", 2, {
    required: false,
  }),
  clearanceField("supporting_document", "Supporting Document", 3, {
    required: false,
  }),
];

const CONTRACT_INTAKE_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "contract_intake_documents",
    label: "Contract intake documents",
    entity: CONTRACT_INTAKE_ENTITY,
    fields: CONTRACT_INTAKE_FIELDS,
  },
];

const CLEARANCE_DESCRIPTION =
  "Operation/clearance documents collected after contract execution, by operation, freight type and customs.";

// ── Driver documents ────────────────────────────────────────────────────────
// Configurable upload area (code "driver_docs") attached to a driver profile —
// license, national ID, contracts, training certificates, etc.
const DRIVER_DOCUMENT_FIELDS: OnboardingField[] = [
  {
    fileKey: "driver_docs",
    fileLabel: "Driver documents",
    helpText: "License, national ID, contracts, training certificates, etc.",
    isRequired: false,
    isMultiple: true,
    maxFiles: 20,
    allowedExtensions: ["pdf", "jpg", "jpeg", "png", "doc", "docx"],
    maxSizeMb: 10,
    displayOrder: 1,
  },
];

const DRIVER_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "driver_docs",
    label: "Driver documents",
    entity: "driver",
    fields: DRIVER_DOCUMENT_FIELDS,
  },
];

// ── Intercity documents ─────────────────────────────────────────────────────
// One shared set for DOMESTIC (intercity) shipments, reviewed by Operations.
// ONE_TIME contracts collect it at contract level after both signatures;
// GENERAL contracts collect it per booking right after the booking is created.
// Fields start empty and are configured in the backoffice file-settings editor.
const INTERCITY_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "intercity_documents",
    label: "Intercity documents",
    entity: "booking",
    fields: [],
  },
];

// ── Hazardous cargo documents ───────────────────────────────────────────────
// Asked for in the contract wizard the moment the customer flags the cargo as
// hazardous (ONE_TIME contracts only). Fields start empty and are configured in
// the backoffice file-settings editor.
const HAZARDOUS_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
  {
    code: "hazardous_documents",
    label: "Hazardous cargo documents",
    entity: CONTRACT_INTAKE_ENTITY,
    fields: [],
  },
];

@Injectable()
export class FileUploadSettingsSeeder {
  private readonly logger = new Logger(FileUploadSettingsSeeder.name);

  constructor(private readonly dataSource: DataSource) { }

  async run() {
    const settingRepository = this.dataSource.getRepository(FileUploadSetting);

    // Seed only into an empty table: any existing rows (including
    // soft-deleted ones, which would still conflict on the unique `code`)
    // mean the data is admin-managed, so leave it untouched.
    const existing = await settingRepository.count({ withDeleted: true });
    if (existing > 0) {
      this.logger.log(
        `file_upload_settings already has ${existing} rows — skipping seed`,
      );
      return;
    }

    const allSettings: Array<
      OnboardingDocumentSetting & { description: string }
    > = [
        ...COMPANY_ONBOARDING_DOCUMENTS.map((s) => ({
          ...s,
          description: COMPANY_ONBOARDING_DESCRIPTION,
        })),
        ...CLEARANCE_DOCUMENT_SETTINGS.map((s) => ({
          ...s,
          description: CLEARANCE_DESCRIPTION,
        })),
        ...CONTRACT_CLEARANCE_SETTINGS.map((s) => ({
          ...s,
          description:
            "Pre-booking clearance documents collected on the contract (Path B), by operation and freight type.",
        })),
        ...SELF_CLEARANCE_SETTINGS.map((s) => ({
          ...s,
          description:
            "Customer self-clearance documents (Path A, no EDR customs service), reviewed by Operations.",
        })),
        ...CONTRACT_INTAKE_SETTINGS.map((s) => ({
          ...s,
          description:
            "Commercial/framework documents attached at contract submission.",
        })),
        ...DRIVER_DOCUMENT_SETTINGS.map((s) => ({
          ...s,
          description:
            "Documents uploaded against a driver profile (license, ID, contracts, etc.).",
        })),
        ...HAZARDOUS_DOCUMENT_SETTINGS.map((s) => ({
          ...s,
          description:
            "Documents required when a one-time contract's cargo is flagged hazardous.",
        })),
        ...INTERCITY_DOCUMENT_SETTINGS.map((s) => ({
          ...s,
          description:
            "Intercity shipment documents — contract-level for ONE_TIME (after both signatures), per booking for GENERAL; reviewed by Operations.",
        })),
      ];

    // Insert setting rows only — no FileUploadField rows. Fields start empty
    // and are configured from the backoffice file-settings editor; the field
    // definitions above are kept as reference defaults.
    await settingRepository.insert(
      allSettings.map((documentSetting) => ({
        code: documentSetting.code,
        label: documentSetting.label,
        description: documentSetting.description,
        entity: documentSetting.entity,
      })),
    );

    this.logger.log(
      `Seeded ${allSettings.length} file upload settings with empty fields`,
    );
  }
}
