import { NextResponse } from "next/server";
import { EterraClient } from "@/modules/parcel-sync/services/eterra-client";
import { getSessionCredentials } from "@/modules/parcel-sync/services/session-store";
import { prisma } from "@/core/storage/prisma";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

type Body = {
  siruta?: string;
  ownerName?: string;
  workspacePk?: number;
  /** "db" = local DB only, "eterra" = eTerra API only, "both" = try both (default) */
  source?: "db" | "eterra" | "both";
};

export type OwnerSearchResult = {
  nrCad: string;
  nrCF: string;
  proprietari: string;
  proprietariVechi: string;
  adresa: string;
  suprafata: number | string;
  intravilan: string;
  categorieFolosinta: string;
  source: "db" | "eterra";
  immovablePk: string;
};

/* ------------------------------------------------------------------ */
/*  Workspace resolution (same as search route)                        */
/* ------------------------------------------------------------------ */

const globalRef = globalThis as {
  __eterraWorkspaceCache?: Map<string, number>;
};
const workspaceCache =
  globalRef.__eterraWorkspaceCache ?? new Map<string, number>();
globalRef.__eterraWorkspaceCache = workspaceCache;

async function resolveWorkspace(
  client: EterraClient,
  siruta: string,
): Promise<number | null> {
  const cached = workspaceCache.get(siruta);
  if (cached !== undefined) return cached;

  try {
    const features = await client.listLayer(
      {
        id: "TERENURI_ACTIVE",
        name: "TERENURI_ACTIVE",
        endpoint: "aut",
        whereTemplate: "{{adminField}}={{siruta}} AND IS_ACTIVE=1",
      },
      siruta,
      { limit: 1, outFields: "WORKSPACE_ID" },
    );

    const wsId = features?.[0]?.attributes?.WORKSPACE_ID;
    if (wsId != null) {
      const numWs = Number(wsId);
      if (Number.isFinite(numWs)) {
        workspaceCache.set(siruta, numWs);
        prisma.gisUat
          .upsert({
            where: { siruta },
            update: { workspacePk: numWs },
            create: { siruta, name: siruta, workspacePk: numWs },
          })
          .catch(() => {});
        return numWs;
      }
    }
  } catch {
    // ArcGIS query failed
  }
  return null;
}

/* ------------------------------------------------------------------ */
/*  DB search — search enrichment JSON for owner name                  */
/* ------------------------------------------------------------------ */

async function searchOwnerInDb(
  siruta: string,
  ownerName: string,
  limit = 50,
): Promise<OwnerSearchResult[]> {
  // Normalize search: remove diacritics for broader matching
  const normalizedSearch = ownerName
    .normalize("NFD")
    .replace(/[\u0300-\u036f]/g, "")
    .toLowerCase()
    .trim();

  // Search in both PROPRIETARI and PROPRIETARI_VECHI fields of enrichment JSON
  // Use raw SQL for ILIKE on JSON text
  const features = await prisma.$queryRaw<
    Array<{
      id: string;
      cadastral_ref: string | null;
      enrichment: Record<string, unknown> | null;
      area_value: number | null;
    }>
  >`
    SELECT id, "cadastralRef" as cadastral_ref, enrichment, "areaValue" as area_value
    FROM "GisFeature"
    WHERE siruta = ${siruta}
      AND "layerId" = 'TERENURI_ACTIVE'
      AND enrichment IS NOT NULL
      AND (
        unaccent(enrichment->>'PROPRIETARI') ILIKE unaccent(${"%" + normalizedSearch + "%"})
        OR unaccent(enrichment->>'PROPRIETARI_VECHI') ILIKE unaccent(${"%" + normalizedSearch + "%"})
      )
    ORDER BY "cadastralRef" ASC
    LIMIT ${limit}
  `;

  return features.map((f) => {
    const e = (f.enrichment ?? {}) as Record<string, unknown>;
    return {
      nrCad: String(e.NR_CAD ?? f.cadastral_ref ?? ""),
      nrCF: String(e.NR_CF ?? ""),
      proprietari: String(e.PROPRIETARI ?? ""),
      proprietariVechi: String(e.PROPRIETARI_VECHI ?? ""),
      adresa: String(e.ADRESA ?? ""),
      suprafata:
        typeof e.SUPRAFATA_2D === "number"
          ? e.SUPRAFATA_2D
          : (f.area_value ?? ""),
      intravilan: String(e.INTRAVILAN ?? ""),
      categorieFolosinta: String(e.CATEGORIE_FOLOSINTA ?? ""),
      source: "db" as const,
      immovablePk: "",
    };
  });
}

/* ------------------------------------------------------------------ */
/*  DB search fallback — without unaccent (if extension not installed) */
/* ------------------------------------------------------------------ */

async function searchOwnerInDbSimple(
  siruta: string,
  ownerName: string,
  limit = 50,
): Promise<OwnerSearchResult[]> {
  const searchPattern = `%${ownerName.trim()}%`;

  const features = await prisma.$queryRaw<
    Array<{
      id: string;
      cadastral_ref: string | null;
      enrichment: Record<string, unknown> | null;
      area_value: number | null;
    }>
  >`
    SELECT id, "cadastralRef" as cadastral_ref, enrichment, "areaValue" as area_value
    FROM "GisFeature"
    WHERE siruta = ${siruta}
      AND "layerId" = 'TERENURI_ACTIVE'
      AND enrichment IS NOT NULL
      AND (
        enrichment->>'PROPRIETARI' ILIKE ${searchPattern}
        OR enrichment->>'PROPRIETARI_VECHI' ILIKE ${searchPattern}
      )
    ORDER BY "cadastralRef" ASC
    LIMIT ${limit}
  `;

  return features.map((f) => {
    const e = (f.enrichment ?? {}) as Record<string, unknown>;
    return {
      nrCad: String(e.NR_CAD ?? f.cadastral_ref ?? ""),
      nrCF: String(e.NR_CF ?? ""),
      proprietari: String(e.PROPRIETARI ?? ""),
      proprietariVechi: String(e.PROPRIETARI_VECHI ?? ""),
      adresa: String(e.ADRESA ?? ""),
      suprafata:
        typeof e.SUPRAFATA_2D === "number"
          ? e.SUPRAFATA_2D
          : (f.area_value ?? ""),
      intravilan: String(e.INTRAVILAN ?? ""),
      categorieFolosinta: String(e.CATEGORIE_FOLOSINTA ?? ""),
      source: "db" as const,
      immovablePk: "",
    };
  });
}

/* ------------------------------------------------------------------ */
/*  eTerra API search — search by owner name via immovable list        */
/* ------------------------------------------------------------------ */

async function searchOwnerOnEterra(
  client: EterraClient,
  workspaceId: number,
  siruta: string,
  ownerName: string,
): Promise<OwnerSearchResult[]> {
  const response = await client.searchImmovableByOwnerName(
    workspaceId,
    siruta,
    ownerName,
    0,
    50,
  );

  const items = response?.content ?? [];
  if (items.length === 0) return [];

  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return items.map((item: any) => ({
    nrCad: String(item?.identifierDetails ?? ""),
    nrCF: String(item?.paperLbNo ?? item?.paperCadNo ?? ""),
    proprietari: "", // Not available from immovable list directly
    proprietariVechi: "",
    adresa: "",
    suprafata: item?.measuredArea ?? item?.legalArea ?? item?.area ?? "",
    intravilan: "",
    categorieFolosinta: "",
    source: "eterra" as const,
    immovablePk: String(item?.immovablePk ?? ""),
  }));
}

/* ------------------------------------------------------------------ */
/*  Route handler                                                      */
/* ------------------------------------------------------------------ */

/**
 * POST /api/eterra/search-owner
 *
 * Search by owner (proprietar/titular) name.
 *
 * Priority: 1) Local DB (enriched features), 2) eTerra API.
 * DB search is fast and rich. eTerra search is slower but works pre-sync.
 */
export async function POST(req: Request) {
  try {
    const body = (await req.json()) as Body;
    const siruta = String(body.siruta ?? "").trim();
    const ownerName = String(body.ownerName ?? "").trim();
    const source = body.source ?? "both";

    if (!siruta || !/^\d+$/.test(siruta)) {
      return NextResponse.json(
        { error: "SIRUTA obligatoriu" },
        { status: 400 },
      );
    }
    if (!ownerName || ownerName.length < 2) {
      return NextResponse.json(
        { error: "Numele proprietarului trebuie să aibă min. 2 caractere." },
        { status: 400 },
      );
    }

    const results: OwnerSearchResult[] = [];
    let dbSearched = false;
    let eterraSearched = false;
    let eterraNote = "";

    /* ── Step 1: DB search ──────────────────────────── */
    if (source !== "eterra") {
      try {
        const dbResults = await searchOwnerInDb(siruta, ownerName);
        results.push(...dbResults);
        dbSearched = true;
      } catch {
        // unaccent extension might not be installed — try simple ILIKE
        try {
          const dbResults = await searchOwnerInDbSimple(siruta, ownerName);
          results.push(...dbResults);
          dbSearched = true;
        } catch (e2) {
          console.log(
            "[search-owner] DB search failed:",
            e2 instanceof Error ? e2.message : e2,
          );
        }
      }
    }

    /* ── Step 2: eTerra API search (if no DB results or source=both) ─ */
    if (source !== "db" && results.length === 0) {
      const session = getSessionCredentials();
      const username = String(
        session?.username || process.env.ETERRA_USERNAME || "",
      ).trim();
      const password = String(
        session?.password || process.env.ETERRA_PASSWORD || "",
      ).trim();

      if (username && password) {
        try {
          const client = await EterraClient.create(username, password);

          // Resolve workspace
          let workspaceId = body.workspacePk ?? null;
          if (!workspaceId || !Number.isFinite(workspaceId)) {
            try {
              const dbUat = await prisma.gisUat.findUnique({
                where: { siruta },
                select: { workspacePk: true },
              });
              if (dbUat?.workspacePk) workspaceId = dbUat.workspacePk;
            } catch {
              // DB lookup failed
            }
          }
          if (!workspaceId || !Number.isFinite(workspaceId)) {
            workspaceId = await resolveWorkspace(client, siruta);
          }

          if (workspaceId) {
            const eterraResults = await searchOwnerOnEterra(
              client,
              workspaceId,
              siruta,
              ownerName,
            );
            // Deduplicate against DB results by nrCad
            const existingCads = new Set(results.map((r) => r.nrCad));
            for (const r of eterraResults) {
              if (!existingCads.has(r.nrCad)) {
                results.push(r);
              }
            }
            eterraSearched = true;
          } else {
            eterraNote =
              "Nu s-a putut determina County/workspace pentru eTerra.";
          }
        } catch (e) {
          eterraNote = `eTerra: ${e instanceof Error ? e.message : "eroare"}`;
        }
      } else {
        eterraNote =
          results.length === 0
            ? "Conectează-te la eTerra pentru a căuta online."
            : "";
      }
    }

    return NextResponse.json({
      results,
      total: results.length,
      dbSearched,
      eterraSearched,
      eterraNote,
    });
  } catch (error) {
    const message = error instanceof Error ? error.message : "Eroare server";
    return NextResponse.json({ error: message }, { status: 500 });
  }
}
