import { redirectToLoginAfterSessionExpired } from "@/features/auth/service/auth-service";

import type {
  CefpIssueMatrixRow,
  CefpIssueMatrixStatus,
  CefpIssueMatrixSummary,
} from "../components/cefp-issue-matrix-data";

type PaginationMeta = {
  page: number;
  limit: number;
  total: number;
  totalPages: number;
};

type ApiResponse<T> = {
  success: boolean;
  statusCode: number;
  message: string;
  data: T;
  meta?: PaginationMeta;
};

type ApiLookup = {
  id: number;
  name: string;
};

type ApiIssueStatus = ApiLookup & {
  code: string;
};

type ApiAgency = ApiLookup & {
  logo: string | null;
};

type ApiCefpIssueMatrixItem = {
  issueId: number;
  issueResolveId: number;
  meetingSummaryId: number;
  title: string;
  description: string;
  recommendation: string;
  category: ApiLookup;
  status: ApiIssueStatus;
  workingGroup: ApiLookup;
  primaryAgency: ApiAgency | null;
  rgcDecision: unknown;
  nextStep: unknown;
  submittedAt: string;
};

const API_URL =
  process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001/api/v1";
const BACKEND_ASSET_URL = API_URL.replace(/\/api(?:\/v\d+)?\/?$/, "");
const FETCH_LIMIT = 50;

function resolveAssetUrl(value: string | null | undefined) {
  if (!value) return null;

  if (
    value.startsWith("http://") ||
    value.startsWith("https://") ||
    value.startsWith("data:") ||
    value.startsWith("blob:")
  ) {
    return value;
  }

  if (value.startsWith("/uploads/")) {
    return `${BACKEND_ASSET_URL}${value}`;
  }

  return value;
}

function stripHtml(value: string) {
  return value
    .replace(/<[^>]*>/g, " ")
    .replace(/&amp;/g, "&")
    .replace(/&nbsp;/g, " ")
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/\s+/g, " ")
    .trim();
}

function toPlainText(value: unknown): string {
  if (value === null || value === undefined) return "-";
  if (typeof value === "string") return stripHtml(value) || "-";

  if (typeof value === "number" || typeof value === "boolean") {
    return String(value);
  }

  try {
    return stripHtml(JSON.stringify(value)) || "-";
  } catch {
    return "-";
  }
}

function normalizeStatus(status: ApiIssueStatus): CefpIssueMatrixStatus {
  switch (status.code) {
    case "SOLVED":
      return "Solved";
    case "IN_PROGRESS":
      return "In Progress";
    case "NOT_ADDRESSED":
      return "Not Addressed";
    case "NEW_SUBMISSION":
      return "New Submission";
    case "DRAFT":
      return "Draft";
    default:
      return "Not Addressed";
  }
}

function getYear(value: string) {
  const date = new Date(value);
  return Number.isNaN(date.getTime()) ? "-" : String(date.getFullYear());
}

function mapCefpIssueMatrixRow(
  item: ApiCefpIssueMatrixItem,
): CefpIssueMatrixRow {
  return {
    id: item.issueId,
    issueId: item.issueId,
    issueResolveId: item.issueResolveId,
    meetingSummaryId: item.meetingSummaryId,
    workingGroupId: item.workingGroup.id,
    workingGroup: item.workingGroup.name.trim() || "-",
    issue: item.title.trim() || "-",
    category: item.category.name.trim() || "-",
    issueDescription: stripHtml(item.description) || "-",
    recommendation: stripHtml(item.recommendation) || "-",
    governmentDecision: toPlainText(item.rgcDecision),
    primaryAgency: item.primaryAgency?.name.trim() || "-",
    primaryAgencyImage: resolveAssetUrl(item.primaryAgency?.logo),
    plenaryEscalation: false,
    status: normalizeStatus(item.status),
    nextStep: toPlainText(item.nextStep),
    submittedAt: item.submittedAt,
    year: getYear(item.submittedAt),
  };
}

function getApiErrorMessage(body: unknown, status: number) {
  if (body && typeof body === "object" && "message" in body) {
    const message = (body as { message?: unknown }).message;

    if (Array.isArray(message)) return message.join(" ");
    if (typeof message === "string" && message.trim()) return message;
  }

  if (status === 401) return "Unauthorized";
  if (status === 403) return "You do not have permission to view CEFP issues.";

  return `Unable to load CEFP issue matrix (${status}).`;
}

async function parseResponseBody(response: Response) {
  const text = await response.text();
  if (!text) return null;

  try {
    return JSON.parse(text) as unknown;
  } catch {
    return text;
  }
}

async function getRequest<T>(path: string): Promise<T> {
  const response = await fetch(`${API_URL}${path}`, {
    method: "GET",
    credentials: "include",
    headers: {
      "Content-Type": "application/json",
    },
  });
  const responseBody = await parseResponseBody(response);

  if (!response.ok) {
    if (response.status === 401) {
      redirectToLoginAfterSessionExpired();
    }

    throw new Error(getApiErrorMessage(responseBody, response.status));
  }

  return responseBody as T;
}

async function getCefpIssueMatrixPage(page: number) {
  return getRequest<ApiResponse<ApiCefpIssueMatrixItem[]>>(
    `/cefp-issue-matrix?page=${page}&limit=${FETCH_LIMIT}`,
  );
}

export async function getCefpIssueMatrixIssues() {
  const firstPage = await getCefpIssueMatrixPage(1);
  const totalPages = firstPage.meta?.totalPages ?? 1;

  if (totalPages <= 1) {
    return (firstPage.data ?? []).map(mapCefpIssueMatrixRow);
  }

  const remainingPageNumbers = Array.from(
    { length: totalPages - 1 },
    (_, index) => index + 2,
  );
  const remainingPages = await Promise.all(
    remainingPageNumbers.map(getCefpIssueMatrixPage),
  );
  const allItems = [
    ...(firstPage.data ?? []),
    ...remainingPages.flatMap((response) => response.data ?? []),
  ];

  return allItems.map(mapCefpIssueMatrixRow);
}

export async function getCefpIssueMatrixSummary() {
  const response = await getRequest<ApiResponse<CefpIssueMatrixSummary>>(
    "/cefp-issue-matrix/summary",
  );

  return response.data;
}
