"use client";

import Link from "next/link";
import { useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader } from "@/components/ui/card";
import { Label } from "@/components/ui/label";
import { Progress } from "@/components/ui/progress";

type ModuleQuestionnaireProps = {
  moduleKey: string;
  moduleName: string;
  moduleDescription: string | null;
  questions: {
    id: string;
    prompt: string;
    helpText: string | null;
    options: {
      id: string;
      label: string;
    }[];
    selectedAnswerOptionId: string | null;
    evidence: {
      notes: string;
      links: string[];
    } | null;
  }[];
  moduleTabs: {
    key: string;
    label: string;
    href: string;
    active: boolean;
  }[];
  previousModuleHref: string | null;
  nextModuleHref: string | null;
  isLastModule: boolean;
};

type EvidenceDraft = {
  notes: string;
  links: string;
};

type SaveState = "idle" | "saving" | "saved" | "error";

type AiQuestionSuggestion = {
  questionId: string;
  suggestedAnswerOptionId: string;
  rationale: string;
  missingEvidence: string[];
  confidence: number | null;
  suggestionId: string;
};

function toEvidenceDraft(
  evidence: {
    notes: string;
    links: string[];
  } | null,
): EvidenceDraft {
  return {
    notes: evidence?.notes ?? "",
    links: evidence?.links.join("\n") ?? "",
  };
}

function toEvidencePayload(draft: EvidenceDraft) {
  const notes = draft.notes.trim();
  const links = draft.links
    .split(/\n|,/g)
    .map((entry) => entry.trim())
    .filter((entry) => entry.length > 0)
    .slice(0, 10);

  if (!notes && links.length === 0) {
    return null;
  }

  return {
    ...(notes ? { notes } : {}),
    ...(links.length > 0 ? { links } : {}),
  };
}

export function ModuleQuestionnaire({
  moduleKey,
  moduleName,
  moduleDescription,
  questions,
  moduleTabs,
  previousModuleHref,
  nextModuleHref,
  isLastModule,
}: ModuleQuestionnaireProps) {
  const [answers, setAnswers] = useState<Record<string, string>>(() => {
    return questions.reduce<Record<string, string>>((result, question) => {
      if (question.selectedAnswerOptionId) {
        result[question.id] = question.selectedAnswerOptionId;
      }

      return result;
    }, {});
  });

  const [evidenceByQuestionId, setEvidenceByQuestionId] = useState<Record<string, EvidenceDraft>>(() => {
    return questions.reduce<Record<string, EvidenceDraft>>((result, question) => {
      result[question.id] = toEvidenceDraft(question.evidence);
      return result;
    }, {});
  });

  const [saveStateByQuestionId, setSaveStateByQuestionId] = useState<Record<string, SaveState>>({});
  const [saveErrorByQuestionId, setSaveErrorByQuestionId] = useState<Record<string, string>>({});
  const [aiSuggestionsByQuestionId, setAiSuggestionsByQuestionId] = useState<Record<string, AiQuestionSuggestion>>({});
  const [isGeneratingAi, setIsGeneratingAi] = useState(false);
  const [aiMessage, setAiMessage] = useState<string | null>(null);
  const [aiError, setAiError] = useState<string | null>(null);
  const [actingSuggestionId, setActingSuggestionId] = useState<string | null>(null);

  const answeredCount = useMemo(() => {
    return questions.reduce((total, question) => {
      return total + (answers[question.id] ? 1 : 0);
    }, 0);
  }, [answers, questions]);

  const completion = questions.length > 0 ? Math.round((answeredCount / questions.length) * 100) : 0;

  function setQuestionSaveState(questionId: string, saveState: SaveState, errorMessage?: string | null) {
    setSaveStateByQuestionId((previous) => ({
      ...previous,
      [questionId]: saveState,
    }));

    setSaveErrorByQuestionId((previous) => {
      const next = { ...previous };

      if (errorMessage) {
        next[questionId] = errorMessage;
      } else {
        delete next[questionId];
      }

      return next;
    });
  }

  async function persistQuestionResponse(questionId: string, answerOptionId: string, evidenceDraft: EvidenceDraft) {
    setQuestionSaveState(questionId, "saving");

    try {
      const response = await fetch("/api/diagnostic/response", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          moduleKey,
          questionId,
          answerOptionId,
          evidence: toEvidencePayload(evidenceDraft),
        }),
      });

      if (!response.ok) {
        const payload = (await response.json().catch(() => ({}))) as { error?: string };
        setQuestionSaveState(questionId, "error", payload.error ?? "No se pudo guardar la respuesta.");
        return false;
      }

      setQuestionSaveState(questionId, "saved");
      return true;
    } catch {
      setQuestionSaveState(questionId, "error", "No se pudo guardar la respuesta.");
      return false;
    }
  }

  function onAnswerChange(questionId: string, answerOptionId: string) {
    setAnswers((previous) => ({
      ...previous,
      [questionId]: answerOptionId,
    }));

    const draft = evidenceByQuestionId[questionId] ?? { notes: "", links: "" };
    void persistQuestionResponse(questionId, answerOptionId, draft);
  }

  function onEvidenceChange(questionId: string, field: keyof EvidenceDraft, value: string) {
    setEvidenceByQuestionId((previous) => ({
      ...previous,
      [questionId]: {
        ...(previous[questionId] ?? { notes: "", links: "" }),
        [field]: value,
      },
    }));
  }

  function onEvidenceSave(questionId: string) {
    const answerOptionId = answers[questionId];

    if (!answerOptionId) {
      setQuestionSaveState(questionId, "error", "Selecciona primero Si/No para guardar evidencia.");
      return;
    }

    const draft = evidenceByQuestionId[questionId] ?? { notes: "", links: "" };
    void persistQuestionResponse(questionId, answerOptionId, draft);
  }

  async function setSuggestionDecision(suggestionId: string, decision: "accept" | "dismiss") {
    const response = await fetch(`/api/ai/suggestions/${encodeURIComponent(suggestionId)}/decision`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ decision }),
    });

    return response.ok;
  }

  async function generateAiSuggestions() {
    setIsGeneratingAi(true);
    setAiError(null);
    setAiMessage(null);

    try {
      const response = await fetch("/api/diagnostic/ai/suggestions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          moduleKey,
        }),
      });

      const payload = (await response.json().catch(() => ({}))) as {
        ok?: boolean;
        error?: string;
        suggestions?: AiQuestionSuggestion[];
      };

      if (!response.ok || !payload.ok || !payload.suggestions) {
        setAiError(payload.error ?? "No fue posible generar sugerencias IA.");
        return;
      }

      const byQuestionId = payload.suggestions.reduce<Record<string, AiQuestionSuggestion>>((accumulator, suggestion) => {
        accumulator[suggestion.questionId] = suggestion;
        return accumulator;
      }, {});

      setAiSuggestionsByQuestionId(byQuestionId);
      setAiMessage(payload.suggestions.length ? "Sugerencias IA actualizadas." : "No hay preguntas pendientes para sugerir.");
    } catch {
      setAiError("No fue posible generar sugerencias IA.");
    } finally {
      setIsGeneratingAi(false);
    }
  }

  async function applyAiSuggestion(questionId: string) {
    const suggestion = aiSuggestionsByQuestionId[questionId];
    if (!suggestion) {
      return;
    }

    setActingSuggestionId(suggestion.suggestionId);
    setAiError(null);
    setAiMessage(null);

    try {
      setAnswers((previous) => ({
        ...previous,
        [questionId]: suggestion.suggestedAnswerOptionId,
      }));

      const draft = evidenceByQuestionId[questionId] ?? { notes: "", links: "" };
      const persisted = await persistQuestionResponse(questionId, suggestion.suggestedAnswerOptionId, draft);

      if (!persisted) {
        setAiError("La sugerencia se aplico localmente, pero no se pudo guardar en el servidor.");
        return;
      }

      await setSuggestionDecision(suggestion.suggestionId, "accept");
      setAiSuggestionsByQuestionId((previous) => {
        const next = { ...previous };
        delete next[questionId];
        return next;
      });
      setAiMessage("Sugerencia IA aplicada.");
    } finally {
      setActingSuggestionId(null);
    }
  }

  async function dismissAiSuggestion(questionId: string) {
    const suggestion = aiSuggestionsByQuestionId[questionId];
    if (!suggestion) {
      return;
    }

    setActingSuggestionId(suggestion.suggestionId);
    setAiError(null);
    setAiMessage(null);

    try {
      await setSuggestionDecision(suggestion.suggestionId, "dismiss");
      setAiSuggestionsByQuestionId((previous) => {
        const next = { ...previous };
        delete next[questionId];
        return next;
      });
      setAiMessage("Sugerencia IA descartada.");
    } finally {
      setActingSuggestionId(null);
    }
  }

  if (questions.length === 0) {
    return (
      <Card>
        <CardHeader>
          <h2 className="text-lg font-semibold text-[#1f2a40]">No hay preguntas disponibles</h2>
        </CardHeader>
        <CardContent className="space-y-4">
          <p className="text-sm text-[#64718a]">Este modulo aun no tiene preguntas configuradas.</p>
          <Link href="/diagnostic">
            <Button variant="secondary">Volver al listado de modulos</Button>
          </Link>
        </CardContent>
      </Card>
    );
  }

  return (
    <div className="space-y-4">
      <div className="flex flex-wrap gap-2 rounded-xl border border-[#dde5f2] bg-white p-3">
        {moduleTabs.map((tab) => (
          <Link key={tab.key} href={tab.href}>
            <Button variant={tab.active ? "primary" : "secondary"} size="sm">
              {tab.label}
            </Button>
          </Link>
        ))}
      </div>

      <Card>
        <CardContent className="space-y-2 py-4">
          <div className="flex flex-wrap items-center justify-between gap-2">
            <p className="text-sm font-semibold text-[#4d5974]">
              {moduleName}
              {moduleDescription ? ` - ${moduleDescription}` : ""}
            </p>
            <p className="text-sm font-semibold text-[#4d5974]">
              {answeredCount} / {questions.length} respondidas
            </p>
          </div>
          <Progress value={completion} showValue />
          <div className="flex flex-wrap items-center gap-2">
            <Button type="button" size="sm" variant="secondary" disabled={isGeneratingAi} onClick={() => void generateAiSuggestions()}>
              {isGeneratingAi ? "Generando sugerencias IA..." : "Generar sugerencias IA"}
            </Button>
            {aiMessage ? <p className="text-sm text-[#1f7c4d]">{aiMessage}</p> : null}
            {aiError ? <p className="text-sm text-[#b63d3d]">{aiError}</p> : null}
          </div>
        </CardContent>
      </Card>

      <Card>
        <CardContent className="space-y-4 py-5">
          {questions.map((question, index) => {
            const selectedOptionId = answers[question.id] ?? null;
            const evidenceDraft = evidenceByQuestionId[question.id] ?? { notes: "", links: "" };
            const saveState = saveStateByQuestionId[question.id] ?? "idle";
            const saveError = saveErrorByQuestionId[question.id] ?? null;
            const aiSuggestion = aiSuggestionsByQuestionId[question.id] ?? null;
            const suggestedOptionLabel =
              question.options.find((option) => option.id === aiSuggestion?.suggestedAnswerOptionId)?.label ?? "Opcion sugerida";

            return (
              <div key={question.id} className="rounded-xl border border-[#d9e2f0] p-4">
                <p className="text-lg font-semibold text-[#1e2b45]">
                  {index + 1}. {question.prompt}
                </p>
                {question.helpText ? <p className="mt-1 text-sm text-[#64718a]">{question.helpText}</p> : null}

                <div className="mt-3 flex flex-wrap gap-2">
                  {question.options.map((option) => (
                    <Label
                      key={option.id}
                      className={`flex cursor-pointer items-center gap-2 rounded-lg border px-3 py-2 font-medium ${
                        selectedOptionId === option.id
                          ? "border-[#0f2a5f] bg-[#eef3ff] text-[#163061]"
                          : "border-[#dde5f2] text-[#3a4963] hover:border-[#b7c6e1]"
                      }`}
                    >
                      <input
                        type="radio"
                        name={`question-${question.id}`}
                        className="h-4 w-4 accent-[#0f2a5f]"
                        checked={selectedOptionId === option.id}
                        onChange={() => onAnswerChange(question.id, option.id)}
                      />
                      {option.label}
                    </Label>
                  ))}
                </div>

                <div className="mt-4 space-y-3">
                  <div>
                    <Label htmlFor={`evidence-notes-${question.id}`}>Evidencia (opcional)</Label>
                    <textarea
                      id={`evidence-notes-${question.id}`}
                      value={evidenceDraft.notes}
                      onChange={(event) => onEvidenceChange(question.id, "notes", event.target.value)}
                      rows={3}
                      className="mt-1 w-full rounded-lg border border-[#cfd8e6] bg-white px-3 py-2 text-sm text-[#1f2a3d] placeholder:text-[#8c96ab] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#0f2a5f]"
                      placeholder="Describe evidencia: certificados, fotos, resultados, etc."
                    />
                  </div>
                  <div>
                    <Label htmlFor={`evidence-links-${question.id}`}>Links de soporte (opcional)</Label>
                    <textarea
                      id={`evidence-links-${question.id}`}
                      value={evidenceDraft.links}
                      onChange={(event) => onEvidenceChange(question.id, "links", event.target.value)}
                      rows={2}
                      className="mt-1 w-full rounded-lg border border-[#cfd8e6] bg-white px-3 py-2 text-sm text-[#1f2a3d] placeholder:text-[#8c96ab] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[#0f2a5f]"
                      placeholder="Un link por linea o separados por coma."
                    />
                  </div>
                </div>

                <div className="mt-3 flex flex-wrap items-center justify-between gap-2">
                  <Button
                    type="button"
                    size="sm"
                    variant="secondary"
                    disabled={saveState === "saving"}
                    onClick={() => onEvidenceSave(question.id)}
                  >
                    Guardar evidencia
                  </Button>

                  {saveState === "saving" ? <p className="text-sm text-[#60708a]">Guardando...</p> : null}
                  {saveState === "saved" ? <p className="text-sm text-[#20724a]">Guardado.</p> : null}
                  {saveState === "error" ? (
                    <p className="rounded-lg border border-[#f6d0d0] bg-[#fff3f3] px-3 py-2 text-sm text-[#9d3030]">
                      {saveError ?? "No se pudo guardar la respuesta."}
                    </p>
                  ) : null}
                </div>

                {aiSuggestion ? (
                  <div className="mt-4 rounded-lg border border-[#d7e2f4] bg-[#f6f9ff] p-3">
                    <p className="text-sm font-semibold text-[#1d335a]">Sugerencia IA</p>
                    <p className="mt-1 text-sm text-[#405578]">
                      Opcion sugerida: <span className="font-semibold">{suggestedOptionLabel}</span>
                    </p>
                    <p className="mt-1 text-sm text-[#506688]">{aiSuggestion.rationale}</p>
                    {aiSuggestion.missingEvidence.length ? (
                      <p className="mt-1 text-xs text-[#60718f]">Evidencia faltante: {aiSuggestion.missingEvidence.join(" | ")}</p>
                    ) : null}
                    {typeof aiSuggestion.confidence === "number" ? (
                      <p className="mt-1 text-xs font-semibold text-[#334d77]">Confianza: {Math.round(aiSuggestion.confidence * 100)}%</p>
                    ) : null}
                    <div className="mt-2 flex flex-wrap items-center gap-2">
                      <Button
                        type="button"
                        size="sm"
                        disabled={actingSuggestionId === aiSuggestion.suggestionId}
                        onClick={() => void applyAiSuggestion(question.id)}
                      >
                        Aplicar
                      </Button>
                      <Button
                        type="button"
                        size="sm"
                        variant="secondary"
                        disabled={actingSuggestionId === aiSuggestion.suggestionId}
                        onClick={() => void dismissAiSuggestion(question.id)}
                      >
                        Descartar
                      </Button>
                    </div>
                  </div>
                ) : null}
              </div>
            );
          })}
        </CardContent>
      </Card>

      <div className="flex flex-wrap items-center justify-between gap-2">
        <div>
          {previousModuleHref ? (
            <Link href={previousModuleHref}>
              <Button variant="ghost">Anterior modulo</Button>
            </Link>
          ) : (
            <Button variant="ghost" disabled>
              Anterior modulo
            </Button>
          )}
        </div>

        <div className="flex gap-2">
          <Link href="/diagnostic">
            <Button variant="secondary">Guardar y salir</Button>
          </Link>

          {isLastModule ? (
            <Link href="/results">
              <Button>Ver mis resultados</Button>
            </Link>
          ) : nextModuleHref ? (
            <Link href={nextModuleHref}>
              <Button>Siguiente modulo</Button>
            </Link>
          ) : (
            <Link href="/diagnostic">
              <Button>Finalizar modulo</Button>
            </Link>
          )}
        </div>
      </div>
    </div>
  );
}
