import type {
  AdminCaseDetail,
  AdminCaseStatus,
  AdminCaseSummary,
  AdminOfficer,
  ScoringOverrideRequest,
} from "./admin-types";
import { officerCanAccessCase } from "./dev-seed-users";
import {
  getDevSession,
  getDevUser,
  listDevSessionIds,
  shouldFallbackToDevMock,
} from "./dev-api-mock";
import { normalizeScore } from "./scoring-normalize";

const DEMO_CASES: AdminCaseSummary[] = [
  {
    id: "case-demo-agrobank",
    financeCaseId: "AGN-FIN-2026-0042",
    farmerName: "Ramesh Pradhan",
    phone: "+998901110002",
    region: "samarkand_region",
    district: "samarkand_city",
    status: "under_review",
    score: 780,
    amountUzs: 150_000_000,
    submittedAt: "2026-06-24T10:00:00.000Z",
    updatedAt: "2026-06-27T08:00:00.000Z",
    preferredInstitution: "inst-uz-agrobank-001",
  },
  {
    id: "case-demo-fc0001",
    financeCaseId: "FC-DEMO0001",
    farmerName: "Jasur Karimov",
    phone: "+998901234567",
    region: "tashkent_region",
    district: "zangiota",
    status: "under_review",
    score: 712,
    amountUzs: 15_000_000,
    submittedAt: "2026-06-20T09:15:00.000Z",
    updatedAt: "2026-06-22T14:30:00.000Z",
  },
  {
    id: "case-demo-002",
    financeCaseId: "FC-DEMO0002",
    farmerName: "Dilnoza Rakhimova",
    phone: "+998907654321",
    region: "fergana_region",
    district: "fergana_city",
    status: "approved",
    score: 768,
    amountUzs: 8_500_000,
    submittedAt: "2026-06-18T11:00:00.000Z",
    updatedAt: "2026-06-21T08:45:00.000Z",
  },
];

const overrides = new Map<string, ScoringOverrideRequest & { officerId: string; overriddenAt: string }>();

function mapSessionStatus(status: string): AdminCaseStatus {
  switch (status) {
    case "draft":
      return "draft";
    case "submitted":
      return "submitted";
    case "scoring":
      return "scoring";
    case "completed":
      return "approved";
    case "failed":
      return "rejected";
    default:
      return "under_review";
  }
}

function financeCaseIdForSession(sessionId: string): string {
  return `FC-${sessionId.slice(-8).toUpperCase()}`;
}

function resolveCaseId(caseId: string): string | null {
  if (getDevSession(caseId)) return caseId;
  const fromFinance = listDevSessionIds().find(
    (id) => financeCaseIdForSession(id) === caseId || financeCaseIdForSession(id) === caseId.toUpperCase(),
  );
  return fromFinance ?? null;
}

function sessionToSummary(sessionId: string): AdminCaseSummary | null {
  const session = getDevSession(sessionId);
  if (!session) return null;

  const user = getDevUser(session.userId);
  const farmProfile = (session.stepData.FARM_PROFILE ?? {}) as Record<string, unknown>;
  const finance = (session.stepData.FINANCE_REQUEST ?? {}) as Record<string, unknown>;
  const scoring = (session.stepData.SCORING ?? {}) as Record<string, unknown>;
  const result = (session.stepData.RESULT ?? {}) as Record<string, unknown>;

  const override = overrides.get(sessionId);
  const score =
    override?.score ??
    (typeof scoring.score === "number" ? scoring.score : null) ??
    (typeof result.score === "number" ? result.score : null);

  let status = mapSessionStatus(session.status);
  if (override) status = "under_review";

  return {
    id: sessionId,
    financeCaseId: financeCaseIdForSession(sessionId),
    farmerName: (farmProfile.fullName as string) ?? "Unknown farmer",
    phone: user?.phone ?? "",
    region: farmProfile.region as string | undefined,
    district: farmProfile.district as string | undefined,
    status,
    score,
    preferredInstitution: finance.preferredInstitution as string | undefined,
    amountUzs: typeof finance.amountUzs === "number" ? finance.amountUzs : null,
    submittedAt:
      session.status !== "draft"
        ? new Date(session.scoringStartedAt ?? Date.now()).toISOString()
        : null,
    updatedAt: new Date().toISOString(),
  };
}

function sessionToDetail(sessionId: string): AdminCaseDetail | null {
  const summary = sessionToSummary(sessionId);
  if (!summary) return null;

  const session = getDevSession(sessionId)!;
  const finance = (session.stepData.FINANCE_REQUEST ?? {}) as Record<string, unknown>;
  const scoring = (session.stepData.SCORING ?? {}) as Record<string, unknown>;
  const override = overrides.get(sessionId);

  const reasonCodes = Array.isArray(scoring.reasonCodes)
    ? (scoring.reasonCodes as AdminCaseDetail["scoring"]["reasonCodes"])
    : [];

  const scoringMeta = (scoring.scoringMeta as Record<string, unknown> | undefined) ?? {};

  return {
    ...summary,
    currentStep: session.currentStepKey,
    completedSteps: [...session.completedSteps],
    financePurpose: finance.purpose as string | undefined,
    preferredInstitution: finance.preferredInstitution as string | undefined,
    scoring: {
      score: summary.score,
      eligibilityOutcome: (scoring.decision as string) ?? (override?.outcome ?? null),
      reasonCodes,
      scoringMeta: {
        ...scoringMeta,
        officerOverride: override
          ? {
              score: override.score,
              outcome: override.outcome,
              notes: override.notes,
              officerId: override.officerId,
              overriddenAt: override.overriddenAt,
            }
          : undefined,
      },
    },
  };
}

export function listAdminCases(officer?: AdminOfficer | null): AdminCaseSummary[] {
  const live = listDevSessionIds()
    .map(sessionToSummary)
    .filter((c): c is AdminCaseSummary => c !== null)
    .filter((c) => c.status !== "draft");

  const merged = [...DEMO_CASES, ...live];
  const seen = new Set<string>();
  const unique = merged.filter((c) => {
    if (seen.has(c.id)) return false;
    seen.add(c.id);
    return true;
  });

  if (!officer) return unique;
  return unique.filter((c) => officerCanAccessCase(officer, c.preferredInstitution));
}

export function getAdminCase(caseId: string, officer?: AdminOfficer | null): AdminCaseDetail | null {
  const demo = DEMO_CASES.find((c) => c.id === caseId || c.financeCaseId === caseId);
  if (demo && !getDevSession(caseId)) {
    if (officer && !officerCanAccessCase(officer, demo.preferredInstitution)) {
      return null;
    }
    return {
      ...demo,
      preferredInstitution: demo.preferredInstitution ?? undefined,
      currentStep: "RESULT",
      completedSteps: ["REVIEW", "SCORING", "RESULT"],
      scoring: {
        score: demo.score,
        eligibilityOutcome: demo.status === "approved" ? "eligible" : "conditional",
        reasonCodes: [
          { code: "RC_NDVI_ANOMALY", feature: "Vegetation health", contribution: 43.2, direction: "positive" as const },
          { code: "RC_DOC_QUALITY", feature: "Document quality", contribution: 63.0, direction: "positive" as const },
        ],
        scoringMeta: {
          modelVersion: "agri-access-uz-v0.1",
          riskRating: "B",
          baselPd: 0.042,
          cbuClass: 2,
          scoringSource: "agri_access",
        },
      },
    };
  }

  const sessionId = resolveCaseId(caseId);
  if (!sessionId) return null;
  const detail = sessionToDetail(sessionId);
  if (detail && officer && !officerCanAccessCase(officer, detail.preferredInstitution)) {
    return null;
  }
  return detail;
}

export function overrideAdminScoring(
  caseId: string,
  body: ScoringOverrideRequest,
  officerId: string,
): AdminCaseDetail | null {
  const sessionId = resolveCaseId(caseId);
  if (!sessionId) return null;

  const session = getDevSession(sessionId);
  if (!session) return null;

  const normalized = normalizeScore(body.score);
  overrides.set(sessionId, {
    ...body,
    score: normalized,
    officerId,
    overriddenAt: new Date().toISOString(),
  });

  const scoring = (session.stepData.SCORING ?? {}) as Record<string, unknown>;
  session.stepData.SCORING = {
    ...scoring,
    score: normalized,
    decision: body.outcome ?? scoring.decision ?? "eligible",
    officerOverride: true,
  };

  return sessionToDetail(sessionId);
}

export function adminApiUsesMock(): boolean {
  return shouldFallbackToDevMock();
}
