import BreadCrumbLink from "@/layouts/shared/page.breadcrumbLink";
import { getGlobalAgent, updateGlobalAgent } from "@/lib/features/chatbot/agent/action";
import { getPromptById } from "@/lib/features/chatbot/prompt/query";
import { updatePrompt } from "@/lib/features/chatbot/prompt/action";
import {
  DEFAULT_TUNING,
  REQUIRED_TUNING_KEYS,
  TUNING_CONFIG,
  type RequiredTuningKey,
} from "@/lib/features/chatbot/constants/constants";
import { useEffect, useRef, useState } from "react";
import { useRevalidator } from "react-router";

import {
  Alert,
  Badge,
  Button,
  Divider,
  Group,
  NumberInput,
  Paper,
  SimpleGrid,
  Stack,
  Text,
  Textarea,
  TextInput,
  Title,
} from "@mantine/core";
import { useForm } from "@mantine/form";
import { IconAlertCircle, IconCheck, IconStar } from "@tabler/icons-react";
import FileUploadField from "../agents/(widgets)/FileUploadField";

export const handle = {
  breadcrumb: () => (
    <BreadCrumbLink
      links={[{ label: "Chatbot" }, { label: "Global Agent" }]}
    />
  ),
};

// ── Loader ─────────────────────────────────────────────────────────────────

export async function loader({ request }: { request: Request }) {
  const headers = { Cookie: request.headers.get("Cookie") ?? "" };

  const agentRes = await getGlobalAgent({ headers } as any);
  const agent = agentRes?.success ? agentRes.data : null;

  let promptContent: string = "";
  let promptName: string = "Trunky Concierge Prompt";

  if (agent?.prompt_id) {
    try {
      const promptRes = await getPromptById(String(agent.prompt_id), { headers } as any);
      const promptData = promptRes?.success ? promptRes.data : null;
      if (promptData) {
        promptContent = promptData.prompt_value ?? "";
        promptName = promptData.prompt_name ?? promptName;
      }
    } catch {
      // non-critical
    }
  }

  return {
    agent,
    promptContent,
    promptName,
    mergedTuning: { ...DEFAULT_TUNING, ...(agent?.tuning_parameters ?? {}) },
  };
}

// ── Types ───────────────────────────────────────────────────────────────────

type LoaderData = {
  agent: {
    id: string;
    agent_name: string;
    prompt_id: string;
    prompt_name?: string;
    data_sources?: { url: string; file_type: string; detected_columns: string[]; sample_values: Record<string, unknown[]> }[];
    language_model: string;
    embed_model: string;
    embed_dimension: number;
    tuning_parameters?: Record<string, number>;
    is_active: boolean;
    is_global: boolean;
    updated_by?: string;
    updated_at?: string;
  } | null;
  promptContent: string;
  promptName: string;
  mergedTuning: Record<string, number>;
};

const getPrecision = (n: number) =>
  String(n).includes(".") ? String(n).split(".")[1].length : 0;

// ── Page component ─────────────────────────────────────────────────────────

export default function GlobalAgentPage({
  loaderData,
}: {
  loaderData: LoaderData;
}) {
  const { agent, promptContent, promptName, mergedTuning } = loaderData;
  const revalidator = useRevalidator();
  const [saving, setSaving] = useState(false);
  const [saved, setSaved] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [isUploading, setIsUploading] = useState(false);
  const savedTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const form = useForm({
    initialValues: {
      prompt_value: promptContent,
      csv_urls: (agent?.data_sources?.map((s: { url: string }) => s.url).filter(Boolean) ?? []) as string[],
      language_model: agent?.language_model ?? "gemini-2.0-flash",
      embed_model: agent?.embed_model ?? "models/text-embedding-004",
      embed_dimension: agent?.embed_dimension ?? 768,
      tuning: mergedTuning as Record<string, number | string>,
    },
    validate: {
      prompt_value: (v) => (v?.trim() ? null : "Prompt content is required."),
      language_model: (v) => (v.trim() ? null : "Required."),
      embed_model: (v) => (v.trim() ? null : "Required."),
      embed_dimension: (v) => (Number(v) > 0 ? null : "Must be > 0."),
    },
    validateInputOnBlur: true,
  });

  // Sync form whenever loaderData refreshes (revalidation after save)
  useEffect(() => {
    if (!agent) return;
    const freshTuning = { ...DEFAULT_TUNING, ...(agent.tuning_parameters ?? {}) };
    form.setValues({
      prompt_value: promptContent,
      language_model: agent.language_model ?? "gemini-2.0-flash",
      embed_model: agent.embed_model ?? "models/text-embedding-004",
      embed_dimension: agent.embed_dimension ?? 768,
      tuning: freshTuning as Record<string, number | string>,
    });
    form.resetDirty();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [agent?.id, agent?.updated_at, promptContent]);

  const handleSave = async (values: typeof form.values) => {
    setError(null);
    setSaving(true);
    setSaved(false);
    if (savedTimerRef.current) clearTimeout(savedTimerRef.current);

    const numericTuning: Record<string, number> = {};
    for (const key in values.tuning) numericTuning[key] = Number(values.tuning[key]);

    try {
      // Save prompt content first
      if (agent?.prompt_id) {
        const promptRes = await updatePrompt(agent.prompt_id, {
          prompt_name: promptName,
          prompt_value: values.prompt_value,
        });
        if (promptRes && (promptRes as any).success === false) {
          throw new Error((promptRes as any).message || "Failed to save prompt.");
        }
      }

      // Save agent configuration
      const globalPayload = {
        csv_urls: values.csv_urls,
        language_model: values.language_model.trim(),
        embed_model: values.embed_model.trim(),
        embed_dimension: Number(values.embed_dimension),
        tuning_parameters: numericTuning,
      };
      const agentRes = await updateGlobalAgent(globalPayload);
      if (agentRes && (agentRes as any).success === false) {
        throw new Error((agentRes as any).message || "Failed to save global agent.");
      }

      setSaved(true);
      revalidator.revalidate();
      savedTimerRef.current = setTimeout(() => setSaved(false), 4000);
    } catch (e: any) {
      setError(e?.message || "Failed to update global agent.");
    } finally {
      setSaving(false);
    }
  };

  if (!agent) {
    return (
      <Alert color="red" icon={<IconAlertCircle />} title="Global Agent not found">
        No global agent found in the database. Please run the seed script to initialise it.
      </Alert>
    );
  }

  return (
    <Stack gap="md" maw={860}>
      {/* Header */}
      <Group gap="xs" align="center">
        <IconStar size={20} color="var(--mantine-color-yellow-6)" />
        <Title order={4}>Global Agent</Title>
        <Badge color="yellow" variant="light" size="sm">main-router</Badge>
        <Badge color="green" variant="dot" size="sm">Always Active</Badge>
      </Group>

      {agent.updated_by && (
        <Text size="xs" c="dimmed">
          Last saved by: <strong>{agent.updated_by}</strong>
          {agent.updated_at && (
            <> &nbsp;·&nbsp; {new Date(agent.updated_at).toLocaleString()}</>
          )}
        </Text>
      )}

      <Text size="sm" c="dimmed">
        The Global Agent is the first agent that handles every user message. It answers
        general questions and routes specialised queries to child agents (Accommodation,
        Maps, Sales, etc.). It is always active and cannot be deleted.
      </Text>

      <Paper withBorder p="lg" radius="md">
        <form onSubmit={form.onSubmit(handleSave)}>
          <Stack gap="md">
            <Divider
              label={
                <Group gap="xs">
                  <Text size="sm" fw={500}>Prompt</Text>
                  <Badge color="blue" variant="light" size="sm">{promptName}</Badge>
                </Group>
              }
            />
            <Textarea
              label="Prompt Content"
              description="The system prompt used by the Global Agent. Changes here are saved immediately."
              placeholder="Enter the system prompt..."
              autosize
              minRows={12}
              maxRows={30}
              required
              error={form.errors.prompt_value}
              {...form.getInputProps("prompt_value")}
            />

            <Divider label="Knowledge Base" />
            <FileUploadField
              label="Data Source Files (CSV / Excel)"
              description="Upload CSV or Excel files for the global agent's knowledge base. Leave empty to use the EXCEL_URL server env var."
              value={form.values.csv_urls}
              onChange={(urls) => form.setFieldValue("csv_urls", urls)}
              onUploadingChange={setIsUploading}
            />

            <Divider label="Model Configuration" />
            <Group grow>
              <TextInput
                label="Language Model"
                placeholder="gemini-2.0-flash"
                required
                error={form.errors.language_model}
                {...form.getInputProps("language_model")}
              />
              <TextInput
                label="Embedding Model"
                placeholder="models/text-embedding-004"
                required
                error={form.errors.embed_model}
                {...form.getInputProps("embed_model")}
              />
              <NumberInput
                label="Embedding Dimension"
                placeholder="768"
                min={1}
                required
                error={form.errors.embed_dimension}
                {...form.getInputProps("embed_dimension")}
              />
            </Group>

            <Divider label="Tuning Parameters" />
            <SimpleGrid cols={3} spacing="lg">
              {REQUIRED_TUNING_KEYS.map((key) => {
                const config = TUNING_CONFIG[key as RequiredTuningKey];
                return (
                  <NumberInput
                    key={key}
                    label={key.replace(/_/g, " ")}
                    description={config.description}
                    step={config.step}
                    decimalScale={getPrecision(config.step)}
                    min={config.min}
                    max={config.max}
                    required
                    {...form.getInputProps(`tuning.${key}`)}
                  />
                );
              })}
            </SimpleGrid>

            {error && (
              <Alert color="red" icon={<IconAlertCircle />} title="Save failed">
                {error}
              </Alert>
            )}
            {saved && (
              <Alert color="green" icon={<IconCheck />} title="Saved">
                Global agent updated successfully.
              </Alert>
            )}

            <Group justify="flex-end">
              <Button
                type="submit"
                loading={saving || revalidator.state === "loading"}
                disabled={!form.isValid() || saving || isUploading}
                leftSection={<IconCheck size={15} />}
              >
                {isUploading ? "Uploading…" : "Save Global Agent"}
              </Button>
            </Group>
          </Stack>
        </form>
      </Paper>
    </Stack>
  );
}
