import type { PageParams, Paginated } from '@/lib/api/types';
import { MOCK_MY_CENTER_ID } from '../constants';
import type {
  CenterInvoice,
  PartnerCenter,
  PartnerCenterApi,
  PartnerCenterFilters,
  PartnerCenterInput,
  SponsoredBooking,
  SponsoredBookingFilters,
  SponsoredNurse,
} from '../types';
import { deriveCenterState } from '../types';

/**
 * In-memory `PartnerCenterApi` — **the primary implementation this phase** (REQ-032/033). Fixtures:
 *  - center **#1 = merchant-of-record** (settlement/invoice view renders) and **#2 = non-MoR** (the
 *    "settlement runs through Balinyaar" state) plus a **draft** center #3 (unverified banner);
 *  - sponsored nurses (verified + unverified) and sponsored bookings;
 *  - commission invoices whose **platform commission + BNPL commission + VAT = total** (VAT on the
 *    commission line only), a fake 22-digit مودیان reference, and a stub PDF url;
 *  - `settlementIbanMasked` is **last-4 only** — the full IBAN never leaves the mock.
 * Admin mutations mutate the in-memory arrays; "my center" resolves to `MOCK_MY_CENTER_ID`.
 */

const DAY_MS = 24 * 60 * 60 * 1000;
const isoDaysAgo = (d: number): string => new Date(Date.now() - d * DAY_MS).toISOString();
const dateDaysAgo = (d: number): string => isoDaysAgo(d).slice(0, 10);

const LATENCY_MS = 220;
const delay = <T>(v: T): Promise<T> => new Promise((r) => setTimeout(() => r(v), LATENCY_MS));

function paginate<T>(all: T[], params: PageParams): Paginated<T> {
  const page = Math.max(1, params.page ?? 1);
  const pageSize = Math.max(1, params.pageSize ?? (all.length || 1));
  const start = (page - 1) * pageSize;
  return { items: all.slice(start, start + pageSize), total: all.length, page, pageSize };
}

/** Mask an IBAN to last-4 (`"••••0001"`) — the mock never surfaces the full value. */
function maskIban(full: string): string {
  return `••••${full.slice(-4)}`;
}

const CENTERS: PartnerCenter[] = [
  {
    id: 1,
    name: 'مرکز پرستاری آسان‌گستر',
    legalEntityType: 'llc',
    mohEstablishmentPermitNo: 'MOH-12345',
    technicalDirectorNurseUserId: 7015,
    technicalDirectorLicenseNo: 'INO-88231',
    enamadCode: 'EN-999',
    settlementIbanMasked: '••••0001',
    isMerchantOfRecord: true,
    commissionRate: 0.05,
    adminUserId: 8,
    isActive: true,
    verifiedAt: isoDaysAgo(40),
    sponsoredNurseCount: 3,
    onboardingState: 'verified',
    createdAt: isoDaysAgo(120),
  },
  {
    id: 2,
    name: 'خانه سلامت مهرآوران',
    legalEntityType: 'cooperative',
    mohEstablishmentPermitNo: 'MOH-55621',
    technicalDirectorNurseUserId: null,
    technicalDirectorLicenseNo: 'INO-44120',
    enamadCode: 'EN-514',
    settlementIbanMasked: '••••7788',
    isMerchantOfRecord: false,
    commissionRate: 0.05,
    adminUserId: 9,
    isActive: true,
    verifiedAt: isoDaysAgo(15),
    sponsoredNurseCount: 1,
    onboardingState: 'verified',
    createdAt: isoDaysAgo(60),
  },
  {
    id: 3,
    name: 'مرکز نمونه (پیش‌نویس)',
    legalEntityType: 'llc',
    mohEstablishmentPermitNo: 'MOH-00099',
    technicalDirectorNurseUserId: null,
    technicalDirectorLicenseNo: null,
    enamadCode: null,
    settlementIbanMasked: null,
    isMerchantOfRecord: false,
    commissionRate: 0.05,
    adminUserId: 10,
    isActive: false,
    verifiedAt: null,
    sponsoredNurseCount: 0,
    onboardingState: 'pending_verification',
    createdAt: isoDaysAgo(5),
  },
];

const NURSES: Record<number, SponsoredNurse[]> = {
  1: [
    { nurseProfileId: 15, name: 'زهرا موسوی', isVerified: true },
    { nurseProfileId: 16, name: 'مریم رضایی', isVerified: true },
    { nurseProfileId: 17, name: 'سارا کاظمی', isVerified: false },
  ],
  2: [{ nurseProfileId: 22, name: 'نگار احمدی', isVerified: true }],
  3: [],
};

const BOOKINGS: Record<number, SponsoredBooking[]> = {
  1: [
    { bookingId: 5001, patientName: 'حاج‌آقا موسوی', scheduledDate: dateDaysAgo(1), status: 'completed' },
    { bookingId: 5002, patientName: 'خانم احمدی', scheduledDate: dateDaysAgo(3), status: 'in_progress' },
    { bookingId: 5003, patientName: 'آقای کریمی', scheduledDate: dateDaysAgo(9), status: 'completed' },
  ],
  2: [{ bookingId: 5101, patientName: 'خانم صادقی', scheduledDate: dateDaysAgo(2), status: 'confirmed' }],
  3: [],
};

/** Build a reconciling commission invoice (VAT on the commission line only; total = comm + bnpl + vat). */
function makeInvoice(id: number, bookingId: number, grossIrr: bigint, commissionIrr: bigint, bnplIrr: bigint, vatRate: number, days: number): CenterInvoice {
  const vatIrr = (commissionIrr * BigInt(Math.round(vatRate * 100))) / BigInt(100);
  const total = commissionIrr + bnplIrr + vatIrr;
  return {
    id,
    bookingId,
    invoiceNumber: `INV-1405-${1000 + id}`,
    grossIrr: String(grossIrr),
    platformCommissionIrr: String(commissionIrr),
    bnplCommissionIrr: bnplIrr > BigInt(0) ? String(bnplIrr) : null,
    vatRate,
    vatIrr: String(vatIrr),
    totalIrr: String(total),
    moadianReferenceNumber: id % 2 === 0 ? '1234567890123456789012' : null,
    moadianStatus: id % 2 === 0 ? 'registered' : 'pending',
    pdfUrl: `https://mock.balinyaar.local/invoices/${id}.pdf`,
    issuedAt: isoDaysAgo(days),
  };
}

const INVOICES: CenterInvoice[] = [
  makeInvoice(1, 5001, BigInt(5_000_000), BigInt(750_000), BigInt(0), 0.1, 2),
  makeInvoice(2, 5003, BigInt(5_000_000), BigInt(750_000), BigInt(60_000), 0.1, 9),
];

function centerById(id: number): PartnerCenter {
  const c = CENTERS.find((x) => x.id === id);
  if (!c) throw new Error(`Mock center ${id} not found`);
  return c;
}

export const partnerCenterMockApi: PartnerCenterApi = {
  listCenters: async (filters: PartnerCenterFilters, params) => {
    let items = [...CENTERS];
    if (filters.isMerchantOfRecord != null) items = items.filter((c) => c.isMerchantOfRecord === filters.isMerchantOfRecord);
    if (filters.isActive != null) items = items.filter((c) => c.isActive === filters.isActive);
    return delay(paginate(items, params));
  },

  getCenter: async (id) => delay(centerById(id)),

  createCenter: async (input: PartnerCenterInput) => {
    const id = Math.max(0, ...CENTERS.map((c) => c.id)) + 1;
    const center: PartnerCenter = {
      id,
      name: input.name,
      legalEntityType: input.legalEntityType,
      mohEstablishmentPermitNo: input.mohEstablishmentPermitNo,
      technicalDirectorNurseUserId: input.technicalDirectorNurseUserId ?? null,
      technicalDirectorLicenseNo: input.technicalDirectorLicenseNo ?? null,
      enamadCode: input.enamadCode ?? null,
      settlementIbanMasked: input.settlementIban ? maskIban(input.settlementIban) : null,
      isMerchantOfRecord: input.isMerchantOfRecord,
      commissionRate: input.commissionRate,
      adminUserId: input.adminUserId ?? null,
      isActive: false,
      verifiedAt: null,
      sponsoredNurseCount: 0,
      onboardingState: 'pending_verification',
      createdAt: new Date().toISOString(),
    };
    CENTERS.push(center);
    NURSES[id] = [];
    BOOKINGS[id] = [];
    return delay(center);
  },

  updateCenter: async (id, input: PartnerCenterInput) => {
    const c = centerById(id);
    Object.assign(c, {
      name: input.name,
      legalEntityType: input.legalEntityType,
      mohEstablishmentPermitNo: input.mohEstablishmentPermitNo,
      technicalDirectorNurseUserId: input.technicalDirectorNurseUserId ?? null,
      technicalDirectorLicenseNo: input.technicalDirectorLicenseNo ?? null,
      enamadCode: input.enamadCode ?? null,
      isMerchantOfRecord: input.isMerchantOfRecord,
      commissionRate: input.commissionRate,
      adminUserId: input.adminUserId ?? null,
    });
    // write-then-masked: a supplied full IBAN is stored masked; never echoed back in plaintext
    if (input.settlementIban) c.settlementIbanMasked = maskIban(input.settlementIban);
    return delay(c);
  },

  verifyCenter: async (id) => {
    const c = centerById(id);
    c.verifiedAt = new Date().toISOString();
    c.isActive = true;
    c.onboardingState = 'verified';
    return delay(undefined);
  },

  setCenterActive: async (id, isActive) => {
    const c = centerById(id);
    c.isActive = isActive;
    c.onboardingState = deriveCenterState(c.isActive, c.verifiedAt);
    return delay(undefined);
  },

  assignNurse: async (id, nurseProfileId, unlink) => {
    const roster = (NURSES[id] ??= []);
    if (unlink) {
      NURSES[id] = roster.filter((n) => n.nurseProfileId !== nurseProfileId);
    } else if (!roster.some((n) => n.nurseProfileId === nurseProfileId)) {
      roster.push({ nurseProfileId, name: `پرستار #${nurseProfileId}`, isVerified: false });
    }
    centerById(id).sponsoredNurseCount = (NURSES[id] ?? []).length;
    return delay(undefined);
  },

  getCenterSponsoredNurses: async (id) => delay([...(NURSES[id] ?? [])]),

  // ── portal (my center) ──
  getMyCenter: async () => delay(centerById(MOCK_MY_CENTER_ID)),
  listMySponsoredNurses: async () => delay([...(NURSES[MOCK_MY_CENTER_ID] ?? [])]),
  listMySponsoredBookings: async (filters: SponsoredBookingFilters, params) => {
    let items = [...(BOOKINGS[MOCK_MY_CENTER_ID] ?? [])];
    if (filters.status) items = items.filter((b) => b.status === filters.status);
    return delay(paginate(items, params));
  },
  listMySettlement: async (params) => {
    const center = centerById(MOCK_MY_CENTER_ID);
    // Non-MoR centers issue no commission invoices here — the portal renders the "via Balinyaar" state.
    const items = center.isMerchantOfRecord ? [...INVOICES] : [];
    return delay(paginate(items, params));
  },
};
