import { createCachedLoader } from "@/services/dropdownCache";
import { DEFAULT_LIST_PAGE, DEFAULT_LIST_PAGE_SIZE } from "@/constants/api";
import { getAuthToken } from "@/utils/token";
import {
  NONE_SELECT_VALUE,
  type SelectOption,
  type VariantQuery,
  type VariantRecord,
} from "./types";

interface BrapiPagination {
  currentPage: number;
  pageSize: number;
  totalCount: number;
  totalPages: number;
}

interface BrapiListResponse<T> {
  metadata: {
    pagination: BrapiPagination;
    status: Array<Record<string, unknown>>;
    datafiles: Array<Record<string, unknown>>;
  };
  result: {
    data: T[];
  };
}

interface BrapiSingleResponse<T> {
  metadata: {
    pagination: BrapiPagination;
    status: Array<Record<string, unknown>>;
    datafiles: Array<Record<string, unknown>>;
  };
  result: T;
}

interface ReferenceSetResponse {
  referenceSetDbId: string;
  referenceSetName: string | null;
}

interface VariantSetResponse {
  variantSetDbId: string;
  variantSetName: string | null;
  referenceSetDbId: string | null;
}

type VariantPayload = Partial<Record<
  | "id"
  | "variant_name"
  | "variant_type"
  | "variant_set_id"
  | "reference_set_id"
  | "start"
  | "end"
  | "reference_bases"
  | "svlen"
  | "filters_applied"
  | "filters_passed",
  unknown
>>;

const apiBase = () => {
  if (typeof window !== "undefined") return "";
  return process.env.API_BASE_URL || process.env.NEXT_PUBLIC_API_BASE_URL || "http://localhost:8000";
};

async function request<T>(path: string, init?: RequestInit): Promise<T> {
  const token = getAuthToken();
  const response = await fetch(`${apiBase()}${path}`, {
    ...init,
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...(init?.headers || {}),
    },
  });

  if (!response.ok) {
    const detail = await response.text();
    throw new Error(detail || `Request failed: ${response.status}`);
  }
  return response.json() as Promise<T>;
}

const optionalText = (value: unknown) => {
  const normalized = String(value ?? "").trim();
  if (!normalized || normalized === NONE_SELECT_VALUE) return null;
  return normalized;
};

const requiredText = (value: unknown, message: string) => {
  const normalized = optionalText(value);
  if (!normalized) throw new Error(message);
  return normalized;
};

const optionalNumber = (value: unknown) => {
  const normalized = optionalText(value);
  if (!normalized) return null;
  const parsed = Number(normalized);
  return Number.isNaN(parsed) ? null : parsed;
};

const optionalBoolean = (value: unknown) => {
  const normalized = optionalText(value);
  if (!normalized) return null;
  return ["true", "1", "pass", "passed"].includes(normalized.toLowerCase());
};

export const mapVariant = (variant: VariantRecord): VariantRecord => ({
  ...variant,
  id: variant.variantDbId || variant.variantId || variant.id,
  variant_name: variant.variant_name
    || variant.variantName
    || (Array.isArray(variant.variantNames) ? variant.variantNames[0] : null)
    || null,
  variant_type: variant.variant_type || variant.variantType || null,
  variant_set_id: variant.variant_set_id
    || variant.variantSetDbId
    || (Array.isArray(variant.variantSetDbId) ? variant.variantSetDbId[0] : null)
    || null,
  variant_set_name: variant.variant_set_name || variant.variantSetName || null,
  reference_set_id: variant.reference_set_id || variant.referenceSetDbId || null,
  reference_set_name: variant.reference_set_name || variant.referenceSetName || null,
  start: variant.start ?? variant.variantStart ?? variant.variant_start ?? null,
  end: variant.end ?? variant.variantEnd ?? variant.variant_end ?? null,
  variant_start: variant.variant_start ?? variant.variantStart ?? variant.start ?? null,
  variant_end: variant.variant_end ?? variant.variantEnd ?? variant.end ?? null,
  reference_bases: variant.reference_bases || variant.referenceBases || null,
  filters_applied: variant.filters_applied ?? variant.filtersApplied ?? null,
  filters_passed: variant.filters_passed ?? variant.filtersPassed ?? null,
});

const variantBody = (payload: VariantPayload) => ({
  variantName: requiredText(payload.variant_name, "Variant name is required"),
  variantType: optionalText(payload.variant_type),
  variantSetDbId: optionalText(payload.variant_set_id),
  referenceSetDbId: optionalText(payload.reference_set_id),
  start: optionalNumber(payload.start),
  end: optionalNumber(payload.end),
  referenceBases: optionalText(payload.reference_bases),
  svlen: optionalNumber(payload.svlen),
  filtersApplied: optionalBoolean(payload.filters_applied),
  filtersPassed: optionalBoolean(payload.filters_passed),
});

export const normalizeVariantFormData = (row: VariantRecord) => ({
  id: row.id,
  variant_name: row.variant_name || "",
  variant_type: row.variant_type && row.variant_type !== NONE_SELECT_VALUE ? row.variant_type : NONE_SELECT_VALUE,
  variant_set_id: row.variant_set_id && row.variant_set_id !== NONE_SELECT_VALUE ? row.variant_set_id : NONE_SELECT_VALUE,
  reference_set_id: row.reference_set_id && row.reference_set_id !== NONE_SELECT_VALUE ? row.reference_set_id : NONE_SELECT_VALUE,
  start: row.start ?? "",
  end: row.end ?? "",
  reference_bases: row.reference_bases || "",
  svlen: row.svlen ?? "",
  filters_applied: row.filters_applied === true ? "true" : row.filters_applied === false ? "false" : NONE_SELECT_VALUE,
  filters_passed: row.filters_passed === true ? "true" : row.filters_passed === false ? "false" : NONE_SELECT_VALUE,
});

const referenceSetLoader = createCachedLoader(async () => {
  const response = await request<BrapiListResponse<ReferenceSetResponse>>("/brapi/v2/referencesets?page=0&pageSize=10");
  return response.result.data;
});

const variantSetLoader = createCachedLoader(async () => {
  const response = await request<BrapiListResponse<VariantSetResponse>>("/brapi/v2/variantsets?page=0&pageSize=10");
  return response.result.data;
});

const variantRowsLoader = createCachedLoader(async () => {
  const response = await request<BrapiListResponse<VariantRecord>>("/brapi/v2/search/variants", {
    method: "POST",
    body: JSON.stringify({ page: DEFAULT_LIST_PAGE, pageSize: DEFAULT_LIST_PAGE_SIZE }),
  });
  return response.result.data.map(mapVariant);
});

function enrichVariantRows(
  rows: VariantRecord[],
  referenceSets: ReferenceSetResponse[],
  variantSets: VariantSetResponse[],
): VariantRecord[] {
  return rows.map((row) => {
    const referenceSet = referenceSets.find((item) => item.referenceSetDbId === row.reference_set_id);
    const variantSet = variantSets.find((item) => item.variantSetDbId === row.variant_set_id);
    return {
      ...row,
      reference_set_name: row.reference_set_name || referenceSet?.referenceSetName || null,
      variant_set_name: row.variant_set_name || variantSet?.variantSetName || null,
    };
  });
}

function filterVariantRows(rows: VariantRecord[], query?: VariantQuery): VariantRecord[] {
  const nameFilter = String(query?.variant_name ?? "").trim().toLowerCase();
  const typeFilter = optionalText(query?.variant_type);
  const variantSetId = optionalText(query?.variant_set_id);
  const referenceSetId = optionalText(query?.reference_set_id);

  return rows.filter((row) => {
    if (nameFilter && !String(row.variant_name ?? "").toLowerCase().includes(nameFilter)) return false;
    if (typeFilter && row.variant_type !== typeFilter) return false;
    if (variantSetId && row.variant_set_id !== variantSetId) return false;
    if (referenceSetId && row.reference_set_id !== referenceSetId) return false;
    return true;
  });
}

function buildVariantOptions(
  referenceSets: ReferenceSetResponse[],
  variantSets: VariantSetResponse[],
) {
  return {
    referenceSets: referenceSets.map((item) => ({
      value: item.referenceSetDbId,
      label: item.referenceSetName || item.referenceSetDbId,
    })),
    variantSets: variantSets.map((item) => ({
      value: item.variantSetDbId,
      label: `${item.variantSetName || item.variantSetDbId}${item.referenceSetDbId ? ` / ${item.referenceSetDbId}` : ""}`,
    })),
  };
}

export function invalidateVariantPageCache() {
  referenceSetLoader.invalidate();
  variantSetLoader.invalidate();
  variantRowsLoader.invalidate();
}

export async function fetchVariantOptions(force = false): Promise<{
  referenceSets: SelectOption[];
  variantSets: SelectOption[];
}> {
  const [referenceSets, variantSets] = await Promise.all([
    referenceSetLoader.load(force),
    variantSetLoader.load(force),
  ]);

  return buildVariantOptions(referenceSets, variantSets);
}

export async function fetchVariantRows(query?: VariantQuery): Promise<VariantRecord[]> {
  const [variants, referenceSets, variantSets] = await Promise.all([
    variantRowsLoader.load(),
    referenceSetLoader.load(),
    variantSetLoader.load(),
  ]);

  return filterVariantRows(enrichVariantRows(variants, referenceSets, variantSets), query);
}

export async function fetchVariantDetail(variantDbId: string): Promise<VariantRecord> {
  const [detail, options, callsResponse] = await Promise.all([
    request<BrapiSingleResponse<VariantRecord>>(`/brapi/v2/variants/${encodeURIComponent(variantDbId)}`),
    fetchVariantOptions(),
    request<BrapiListResponse<Record<string, never>>>(`/brapi/v2/variants/${encodeURIComponent(variantDbId)}/calls?pageSize=10`),
  ]);

  const mapped = mapVariant(detail.result);
  const referenceSet = options.referenceSets.find((item) => item.value === mapped.reference_set_id);
  const variantSet = options.variantSets.find((item) => item.value === mapped.variant_set_id);

  return {
    ...mapped,
    reference_set_name: mapped.reference_set_name || referenceSet?.label || null,
    variant_set_name: mapped.variant_set_name || variantSet?.label || null,
    allele_call_count: callsResponse.result.data.length,
  };
}

export async function createVariantRow(payload: VariantPayload): Promise<VariantRecord> {
  const response = await request<BrapiListResponse<VariantRecord>>("/brapi/v2/variants", {
    method: "POST",
    body: JSON.stringify({
      variantDbId: requiredText(payload.id, "Variant ID is required"),
      ...variantBody(payload),
    }),
  });
  invalidateVariantPageCache();
  return mapVariant(response.result.data[0]);
}

export async function updateVariantRow(id: string, payload: VariantPayload): Promise<VariantRecord> {
  const requestedId = optionalText(payload.id);
  if (requestedId && requestedId !== id) throw new Error("Variant ID is immutable. Create a new record instead.");
  const response = await request<BrapiSingleResponse<VariantRecord>>(`/brapi/v2/variants/${encodeURIComponent(id)}`, {
    method: "PUT",
    body: JSON.stringify(variantBody(payload)),
  });
  invalidateVariantPageCache();
  return mapVariant(response.result);
}

export async function deleteVariantRow(id: string): Promise<void> {
  await request<BrapiSingleResponse<VariantRecord>>(`/brapi/v2/variants/${encodeURIComponent(id)}`, {
    method: "DELETE",
  });
  invalidateVariantPageCache();
}

export async function loadVariantPageData(options?: { query?: VariantQuery; force?: boolean }) {
  const force = options?.force ?? false;
  const [referenceSets, variantSets, variants] = await Promise.all([
    referenceSetLoader.load(force),
    variantSetLoader.load(force),
    variantRowsLoader.load(force),
  ]);

  const enrichedRows = enrichVariantRows(variants, referenceSets, variantSets);
  return {
    options: buildVariantOptions(referenceSets, variantSets),
    rows: filterVariantRows(enrichedRows, options?.query),
  };
}
