import {
  IconAnchor,
  IconArrowsExchange,
  IconFileDescription,
  IconId,
  IconRubberStamp,
  IconShieldCheck,
  IconShip,
  IconTruck,
  IconUsers,
  type Icon,
} from '@tabler/icons-react';
import type { LicenseApplication, LicenseType } from '@ema-platform/api';

/**
 * Presentation-only metadata per licence type.
 *
 * Deliberately thin. Everything that actually varies between licence types —
 * fees, capital threshold, validity, whether an inspection is required,
 * whether a certificate is issued, the form schema, the document and staff
 * requirements — already lives in the `license_types` table and arrives from
 * `GET /license-types`. The API entity states the rule outright: onboarding a
 * new type is meant to be a seed or admin change, not a code change
 * (BR-MTO-020).
 *
 * Duplicating any of that here would fork the source of truth and mean a new
 * licence type silently rendered with another type's rules. So this file holds
 * only what the database has no opinion about: which icon to draw, and the
 * order review tabs appear in.
 */
export interface LicenseTypePresentation {
  /** Matches `LicenseType.key`. */
  key: string;
  icon: Icon;
  /** Review tabs, in order. Tabs with no data do not render. */
  detailSections: DetailSection[];
}

export type DetailSection =
  | 'overview'
  | 'company'
  | 'financials'
  | 'documents'
  | 'staff'
  | 'inspection';

const DEFAULT_SECTIONS: DetailSection[] = [
  'overview',
  'company',
  'financials',
  'documents',
  'staff',
  'inspection',
];

const PRESENTATION: Record<string, LicenseTypePresentation> = {
  FREIGHT_FORWARDER: {
    key: 'FREIGHT_FORWARDER',
    icon: IconTruck,
    detailSections: DEFAULT_SECTIONS,
  },
  SHIPPING_AGENT: {
    key: 'SHIPPING_AGENT',
    icon: IconShip,
    detailSections: DEFAULT_SECTIONS,
  },
  COMBINED_SA_FF: {
    key: 'COMBINED_SA_FF',
    icon: IconFileDescription,
    detailSections: DEFAULT_SECTIONS,
  },
  JOINT_INVESTOR: {
    key: 'JOINT_INVESTOR',
    icon: IconUsers,
    // Terminates at COMPLETED with no payment and no certificate, and the
    // workflow skips inspection for it.
    detailSections: ['overview', 'company', 'financials', 'documents', 'staff'],
  },
  MULTIMODAL_TRANSPORT_OPERATOR: {
    key: 'MULTIMODAL_TRANSPORT_OPERATOR',
    icon: IconAnchor,
    detailSections: DEFAULT_SECTIONS,
  },
  SEAFARER_REGISTRATION: {
    key: 'SEAFARER_REGISTRATION',
    icon: IconId,
    // Person-centric: no company entity, no capital threshold, no staff roles.
    detailSections: ['overview', 'documents'],
  },
  // Opened automatically when a registration is approved, and reviewed like any
  // other person-centric service. Listed explicitly because neither key matches
  // the certificate prefixes below, so both fell through to the company-shaped
  // default and offered an officer Company, Financials and Staff tabs for an
  // application about one person.
  SEAMAN_BOOK: {
    key: 'SEAMAN_BOOK',
    icon: IconId,
    // Its own TRB inspection is a real stage, unlike the other personal
    // services, so the inspection tab stays.
    detailSections: ['overview', 'documents', 'inspection'],
  },
  BTC_BASIC_TRAINING: {
    key: 'BTC_BASIC_TRAINING',
    icon: IconShieldCheck,
    detailSections: ['overview', 'documents'],
  },
  VESSEL_REGISTRATION: {
    key: 'VESSEL_REGISTRATION',
    icon: IconAnchor,
    detailSections: DEFAULT_SECTIONS,
  },
  VESSEL_OWNERSHIP_TRANSFER: {
    key: 'VESSEL_OWNERSHIP_TRANSFER',
    icon: IconArrowsExchange,
    // Transfers an existing registration between owners: no company entity,
    // no capital threshold, no staff roles.
    detailSections: ['overview', 'documents'],
  },
  ENDORSEMENT_SEAFARER: {
    key: 'ENDORSEMENT_SEAFARER',
    icon: IconRubberStamp,
    // Person-centric, same as seafarer registration: no company entity, no
    // capital threshold, no staff roles, no inspection. Covers CoC and GOC
    // together — the `endorsementScope` field on the application decides
    // which certificate section(s) actually have data.
    detailSections: ['overview', 'documents'],
  },
  // Retired by ENDORSEMENT_SEAFARER (see endorsements.seed-data.ts). Kept so
  // an application filed before the switch still renders with the right
  // presentation instead of falling back to the generic company layout.
  ENDORSEMENT_COC: {
    key: 'ENDORSEMENT_COC',
    icon: IconRubberStamp,
    detailSections: ['overview', 'documents'],
  },
  ENDORSEMENT_GOC: {
    key: 'ENDORSEMENT_GOC',
    icon: IconRubberStamp,
    detailSections: ['overview', 'documents'],
  },
};

/**
 * A seafarer certificate is judged on the person, not a company.
 *
 * Matched by prefix rather than listed: the catalogue holds over fifty
 * rank-specific CoC/CoP keys and grows whenever EMA configures another, and an
 * explicit map would silently fall back to the company presentation — showing
 * a reviewing officer capital, staff-role and inspection tabs that a
 * certificate application can never fill.
 */
const CERTIFICATE_KEY_PREFIXES = ['COC_', 'COP_', 'GOC_'];
const CERTIFICATE_SECTIONS: DetailSection[] = ['overview', 'documents'];

/**
 * CoC, CoP and the endorsement/GOC family: a seafarer's own certificate rather
 * than an organisation's licence. They skip the claim/assign queue — see
 * `resolveActions`.
 */
export function isSeafarerCertificate(key: string | undefined): boolean {
  if (!key) return false;
  return (
    CERTIFICATE_KEY_PREFIXES.some((prefix) => key.startsWith(prefix)) ||
    key === 'CERTIFICATE_OF_COMPETENCY' ||
    key === 'CERTIFICATE_OF_PROFICIENCY'
  );
}

/** Falls back to a generic presentation so an unseeded type still renders. */
export function presentationFor(key: string | undefined): LicenseTypePresentation {
  if (key && PRESENTATION[key]) return PRESENTATION[key];

  if (key && isSeafarerCertificate(key)) {
    return {
      key,
      icon: IconShieldCheck,
      detailSections: CERTIFICATE_SECTIONS,
    };
  }

  return {
    key: key ?? 'UNKNOWN',
    icon: IconFileDescription,
    detailSections: DEFAULT_SECTIONS,
  };
}

export const LICENSE_TYPE_KEYS = Object.keys(PRESENTATION);

// ---------------------------------------------------------------- eligibility

export interface EligibilityRule {
  id: string;
  /** Plain-language statement of the rule, already interpolated. */
  label: string;
  /** What the application actually declares/verifies, formatted. */
  actual: string;
  status: 'pass' | 'fail' | 'unknown';
}

/**
 * Turns the licence type's configured thresholds into a checked list.
 *
 * The capital threshold used to be applied invisibly — the officer saw a
 * disabled approve button and had to know why. Rendering it as an explicit
 * pass/fail line means the rule, the figure it was checked against, and the
 * outcome are all on screen.
 */
/** Loose enough to accept i18next's real `t` structurally — see sla.ts for
 *  why this can't just be typed as `TFunction`. */
type Translate = (key: string, options?: unknown) => string;

export function evaluateEligibility(
  application: LicenseApplication,
  licenseType: LicenseType | undefined,
  locale: string,
  t: Translate,
): EligibilityRule[] {
  const rules: EligibilityRule[] = [];

  const threshold =
    licenseType?.capitalThreshold == null
      ? undefined
      : Number(licenseType.capitalThreshold);

  if (threshold !== undefined && !Number.isNaN(threshold)) {
    const verified =
      application.capitalAmountVerified == null
        ? undefined
        : Number(application.capitalAmountVerified);
    const declared =
      application.capitalAmountDeclared == null
        ? undefined
        : Number(application.capitalAmountDeclared);
    const effective = verified ?? declared;
    const currency = licenseType?.feeCurrency ?? 'ETB';
    const format = (value: number) =>
      `${value.toLocaleString(locale)} ${currency}`;

    rules.push({
      id: 'capital-threshold',
      label: t('review.eligibilityRule.capitalThreshold', {
        amount: format(threshold),
        defaultValue: 'Paid-up capital ≥ {{amount}}',
      }),
      actual:
        effective === undefined
          ? t('review.eligibilityRule.notRecorded', 'Not recorded')
          : `${format(effective)}${
              verified === undefined
                ? t('review.eligibilityRule.declaredSuffix', ' (declared)')
                : t('review.eligibilityRule.verifiedSuffix', ' (verified)')
            }`,
      // An unverified declaration is not evidence, so it reads as unknown
      // rather than as a pass the officer never actually made.
      status:
        effective === undefined || verified === undefined
          ? 'unknown'
          : effective >= threshold
            ? 'pass'
            : 'fail',
    });
  }

  if (licenseType?.inspectionRequired) {
    const inspected = [
      'INSPECTION_COMPLETED',
      'APPROVED',
      'PAYMENT_PENDING',
      'PAID',
      'PAYMENT_CONFIRMED',
      'CERTIFICATE_ISSUED',
      'COMPLETED',
    ].includes(application.status);
    rules.push({
      id: 'inspection',
      label: t('review.eligibilityRule.inspectionCompleted', 'Physical inspection completed'),
      actual: inspected
        ? t('review.eligibilityRule.recorded', 'Recorded')
        : t('review.eligibilityRule.notYetRecorded', 'Not yet recorded'),
      status: inspected ? 'pass' : 'unknown',
    });
  }

  return rules;
}
