import type { BaseQueryFn } from '@reduxjs/toolkit/query/react';
import type { FetchArgs, FetchBaseQueryError } from '@reduxjs/toolkit/query';
import { baseQueryWithReauth } from './base-query-with-reauth';
import {
  mockApplicationDetails,
  mockApplications,
  mockLicenses,
  mockLicenseTypeRequirements,
  mockLicenseTypes,
  mockMyExamAppeals,
  mockMyExamRegistrations,
  mockMyExamResults,
  mockNotifications,
  mockOpenExams,
  mockProfileMeResponse,
  mockVessels,
} from './mock-data';

/**
 * Dev-only mock `BaseQueryFn`, opt-in via `VITE_USE_MOCKS=true` (see
 * `base-api/index.ts`).
 *
 * Design choice: this is a partial mock, not a full fake backend. Each
 * handler below matches a specific method + URL pattern for the four preview
 * feature areas (vessel registration, seafarer registration, CoC
 * certificates, exams) plus the shared profile/permissions/licensing-config
 * endpoints they depend on. Anything not matched here falls through to the
 * real `baseQueryWithReauth`, so login, signup, and any endpoint outside the
 * four areas keep talking to a real backend if one is reachable. This was
 * chosen over a full-mock/404 approach so the rest of the app (profile
 * editing, payments, other license types, backoffice) is unaffected and a
 * developer can extend coverage incrementally by adding more handlers below.
 *
 * Extend by adding another entry to `handlers`. Each handler receives the
 * parsed method/path/params/body and returns the response payload (or
 * `undefined` to fall through to the next handler / the real backend).
 */

type MockRequest = {
  method: string;
  path: string;
  params?: Record<string, unknown>;
  body?: unknown;
};

type MockHandler = {
  method: string;
  /** Matches the URL path (query string stripped). */
  pattern: RegExp;
  respond: (req: MockRequest, match: RegExpMatchArray) => unknown;
};

function clone<T>(value: T): T {
  return JSON.parse(JSON.stringify(value));
}

function paginated<T>(items: T[]) {
  return { total: items.length, items };
}

let mockAppSeq = 100;

const handlers: MockHandler[] = [
  // --------------------------------------------------------------- profile
  {
    method: 'GET',
    pattern: /^\/profiles\/me$/,
    respond: () => clone(mockProfileMeResponse),
  },

  // ----------------------------------------------------------- license types
  {
    method: 'GET',
    pattern: /^\/license-types$/,
    respond: () => paginated(clone(mockLicenseTypes)),
  },
  {
    method: 'GET',
    pattern: /^\/license-types\/requirements\/([\w-]+)$/,
    respond: (_req, match) => {
      const key = match[1];
      const found = mockLicenseTypeRequirements[key];
      return found ? clone(found) : undefined;
    },
  },
  {
    method: 'GET',
    pattern: /^\/license-categories$/,
    respond: () =>
      paginated([
        { key: 'MARITIME_PERSONNEL', name: { en: 'Maritime Personnel' }, description: { en: 'Seafarer and vessel services' }, sortOrder: 1 },
      ]),
  },
  {
    method: 'GET',
    pattern: /^\/profiles\/me\/operations$/,
    respond: () => ({ items: [] }),
  },

  // ----------------------------------------------------------- applications
  {
    method: 'GET',
    pattern: /^\/license-applications\/mine$/,
    respond: () => paginated(clone(Object.values(mockApplications))),
  },
  {
    method: 'POST',
    pattern: /^\/license-applications$/,
    respond: (req) => {
      const body = (req.body ?? {}) as { licenseType?: string; kind?: string; previousLicenseId?: string };
      const typeKey = body.licenseType ?? 'VESSEL_REGISTRATION';
      const requirements = mockLicenseTypeRequirements[typeKey];
      const id = `app-draft-${++mockAppSeq}`;
      const now = new Date().toISOString();
      const application = {
        id,
        applicationNumber: `${requirements?.licenseType.certificatePrefix ?? 'APP'}-2026-${String(mockAppSeq).padStart(6, '0')}`,
        licenseTypeId: requirements?.licenseType.id ?? 'license-type-unknown',
        licenseType: requirements?.licenseType ?? { id: 'license-type-unknown', key: typeKey, name: { en: typeKey } },
        applicantUserId: 'user-mock-001',
        kind: body.kind ?? 'NEW',
        status: 'DRAFT',
        assignedOfficerId: null,
        claimedAt: null,
        formData: {},
        companyName: null,
        tradeName: null,
        tinNumber: null,
        businessAddress: null,
        capitalAmountDeclared: null,
        capitalAmountVerified: null,
        adjustmentRound: 0,
        submittedAt: null,
        decidedAt: null,
        rejectionReason: null,
        feeAmount: String(requirements?.fee ?? ''),
        feeCurrency: requirements?.feeCurrency ?? 'ETB',
        issuedLicenseId: null,
        createdAt: now,
      };
      mockApplications[id] = application;
      mockApplicationDetails[id] = {
        application,
        staff: [],
        attachments: [],
        history: [
          {
            id: `hist-${id}-1`,
            fromStatus: null,
            toStatus: 'DRAFT',
            event: 'created',
            actorUserId: 'user-mock-001',
            actorName: 'Abebe Tesfaye',
            actorRole: 'APPLICANT',
            remark: null,
            metadata: null,
            createdAt: now,
          },
        ],
        remarks: [],
        openRemarks: [],
        availableEvents: [],
      };
      return clone(application);
    },
  },
  {
    method: 'GET',
    pattern: /^\/license-applications\/([\w-]+)$/,
    respond: (_req, match) => {
      const detail = mockApplicationDetails[match[1]];
      return detail ? clone(detail) : undefined;
    },
  },
  {
    method: 'DELETE',
    pattern: /^\/license-applications\/([\w-]+)$/,
    respond: (_req, match) => {
      delete mockApplications[match[1]];
      delete mockApplicationDetails[match[1]];
      return { deleted: true };
    },
  },
  {
    method: 'PATCH',
    pattern: /^\/license-applications\/([\w-]+)\/sections\/([\w-]+)$/,
    respond: (req, match) => {
      const [, id, sectionKey] = match;
      const application = mockApplications[id];
      if (!application) return undefined;
      const body = (req.body ?? {}) as { values?: Record<string, unknown> };
      application.formData = { ...application.formData, [sectionKey]: body.values ?? {} };
      return clone(application);
    },
  },
  {
    method: 'POST',
    pattern: /^\/license-applications\/([\w-]+)\/submit$/,
    respond: (_req, match) => {
      const application = mockApplications[match[1]];
      if (!application) return undefined;
      application.status = 'UNDER_REVIEW';
      application.submittedAt = new Date().toISOString();
      return clone(application);
    },
  },
  {
    method: 'POST',
    pattern: /^\/license-applications\/([\w-]+)\/resubmit$/,
    respond: (_req, match) => {
      const application = mockApplications[match[1]];
      if (!application) return undefined;
      application.status = 'UNDER_REVIEW';
      return clone(application);
    },
  },
  {
    method: 'PATCH',
    pattern: /^\/license-applications\/([\w-]+)\/remarks\/([\w-]+)\/resolve$/,
    respond: () => ({ ok: true }),
  },
  {
    method: 'POST',
    pattern: /^\/license-applications\/([\w-]+)\/staff$/,
    respond: (req) => {
      const body = (req.body ?? {}) as { roleKey?: string; fullName?: string; position?: string; yearsOfExperience?: number };
      return {
        id: `staff-mock-${Date.now()}`,
        roleKey: body.roleKey ?? '',
        fullName: body.fullName ?? '',
        position: body.position ?? null,
        roleCategory: null,
        yearsOfExperience: body.yearsOfExperience ?? null,
        documents: [],
      };
    },
  },
  {
    method: 'DELETE',
    pattern: /^\/license-applications\/([\w-]+)\/staff\/([\w-]+)$/,
    respond: () => ({ ok: true }),
  },

  // -------------------------------------------------------------- licenses
  {
    method: 'GET',
    pattern: /^\/licenses\/mine$/,
    respond: () => paginated(clone(mockLicenses)),
  },
  {
    method: 'GET',
    pattern: /^\/licenses\/([\w-]+)\/certificate$/,
    respond: (_req, match) => ({
      url: `https://example-cdn.ema.gov.et/certificates/${match[1]}.pdf`,
    }),
  },

  // ------------------------------------------------------------ attachments
  {
    method: 'GET',
    pattern: /^\/attachments$/,
    respond: () => [],
  },

  // ---------------------------------------------------------- notifications
  {
    method: 'GET',
    pattern: /^\/notifications\/unseen$/,
    respond: () => clone(mockNotifications),
  },
  {
    method: 'GET',
    pattern: /^\/notifications$/,
    respond: () => clone(mockNotifications),
  },
  {
    method: 'PATCH',
    pattern: /^\/notifications\/([\w-]+)\/read$/,
    respond: () => ({ ok: true }),
  },

  // ---------------------------------------------------------------- vessels
  {
    method: 'GET',
    pattern: /^\/vessels\/mine$/,
    respond: () => clone(mockVessels),
  },
  {
    method: 'POST',
    pattern: /^\/vessels\/([\w-]+)\/incidents$/,
    respond: (req, match) => ({
      id: `incident-mock-${Date.now()}`,
      vesselId: match[1],
      occurredAt: (req.body as { occurredAt?: string })?.occurredAt ?? new Date().toISOString(),
      location: (req.body as { location?: string })?.location ?? null,
      description: (req.body as { description?: string })?.description ?? '',
      severity: null,
      reportedById: 'user-mock-001',
      reportedByOfficer: false,
      createdAt: new Date().toISOString(),
    }),
  },

  // ------------------------------------------------------------------ exams
  {
    method: 'GET',
    pattern: /^\/exams\/open$/,
    respond: () => clone(mockOpenExams),
  },
  {
    method: 'GET',
    pattern: /^\/exams\/registrations\/mine$/,
    respond: () => clone(mockMyExamRegistrations),
  },
  {
    method: 'POST',
    pattern: /^\/exams\/([\w-]+)\/register$/,
    respond: () => ({ admissionNumber: `ADM-2026-${Math.floor(Math.random() * 900000 + 100000)}` }),
  },
  {
    method: 'GET',
    pattern: /^\/results\/mine$/,
    respond: () => clone(mockMyExamResults),
  },
  {
    method: 'GET',
    pattern: /^\/results\/appeals\/mine$/,
    respond: () => clone(mockMyExamAppeals),
  },
  {
    method: 'POST',
    pattern: /^\/results\/([\w-]+)\/appeal$/,
    respond: () => ({ appealNumber: `APL-2026-${Math.floor(Math.random() * 900000 + 100000)}` }),
  },

  // -------------------------------------------------------- seafarer records
  {
    method: 'GET',
    pattern: /^\/sea-service-records\/mine$/,
    respond: () => [],
  },
  {
    method: 'GET',
    pattern: /^\/medical-certificates\/mine$/,
    respond: () => [],
  },
  {
    method: 'GET',
    pattern: /^\/sea-service-records\/mine\/sea-time$/,
    respond: () => ({ totalDays: 620, verifiedRecords: 4 }),
  },
];

function parseArgs(args: string | FetchArgs): { method: string; path: string; params?: Record<string, unknown>; body?: unknown } {
  if (typeof args === 'string') {
    const [path] = args.split('?');
    return { method: 'GET', path };
  }
  const [path] = (args.url ?? '').split('?');
  return {
    method: (args.method ?? 'GET').toUpperCase(),
    path,
    params: args.params as Record<string, unknown> | undefined,
    body: args.body,
  };
}

function delay(ms: number) {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

export const mockBaseQuery: BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError> = async (
  args,
  api,
  extraOptions,
) => {
  const req = parseArgs(args);

  for (const handler of handlers) {
    if (handler.method !== req.method) continue;
    const match = req.path.match(handler.pattern);
    if (!match) continue;

    const data = handler.respond(req, match);
    if (data === undefined) continue;

    await delay(150 + Math.floor(Math.random() * 150));
    return { data };
  }

  // Unmatched — fall through to the real backend (auth/login, and any
  // endpoint outside the four mocked preview areas).
  return baseQueryWithReauth(args, api, extraOptions);
};
