"use client";

import { useEffect, useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import {
  initialApplicantsByPosition,
  readApplicantsFromStorage,
  writeApplicantsToStorage,
  type Applicant,
} from "@/components/initialPositionsData";
import { appendEventToStorage } from "@/components/eventStream";

type Stage = {
  id: string;
  title: string;
  subtitle: string;
};

export type StageMoveEvent = {
  eventType: "applicant_stage_moved";
  applicantId: string;
  applicantName: string;
  fromStageId: string;
  toStageId: string;
  movedAt: string;
};

type ApplicantsSectionProps = {
  positionId: string;
  positionTitle: string;
  onApplicantStageMove?: (event: StageMoveEvent) => void;
};

const stages: Stage[] = [
  {
    id: "new_applied",
    title: "New/Applied",
    subtitle: "New applicant submissions and recent applicants",
  },
  {
    id: "resume_review_screening",
    title: "Resume Review / Screening",
    subtitle: "Initial review and screening in progress",
  },
  {
    id: "offer_letter_sent",
    title: "Offer Letter Sent",
    subtitle: "Offer package has been sent to applicant",
  },
  {
    id: "hired_or_closed",
    title: "Hired or Closed",
    subtitle: "Applicant hired or role closed out",
  },
];

const stageIds = new Set(stages.map((stage) => stage.id));
const stageTitleById = stages.reduce<Record<string, string>>((acc, stage) => {
  acc[stage.id] = stage.title;
  return acc;
}, {});

function toNumber(value: unknown) {
  if (typeof value === "number" && Number.isFinite(value)) {
    return value;
  }
  if (typeof value === "string") {
    const parsed = Number(value);
    if (Number.isFinite(parsed)) {
      return parsed;
    }
  }
  return null;
}

function recommendationScore(recommendation?: "hire" | "no_hire" | "strong_hire") {
  if (recommendation === "strong_hire") {
    return 100;
  }
  if (recommendation === "hire") {
    return 80;
  }
  if (recommendation === "no_hire") {
    return 30;
  }
  return null;
}

function recommendationLabel(recommendation?: "hire" | "no_hire" | "strong_hire") {
  if (recommendation === "strong_hire") {
    return "Strong Hire";
  }
  if (recommendation === "hire") {
    return "Hire";
  }
  if (recommendation === "no_hire") {
    return "No Hire";
  }
  return "Not submitted";
}

function computeApplicantCompositeScore(applicant: Applicant) {
  const aiFitScore = toNumber(applicant.screeningEvaluation?.overall_fit_score);
  const scorecardRating = applicant.scorecard?.rating ?? null;
  const scorecardRatingNormalized =
    typeof scorecardRating === "number" ? (scorecardRating / 5) * 100 : null;
  const recommendationNormalized = recommendationScore(applicant.scorecard?.recommendation);

  const weightedParts: number[] = [];
  const weightedTotalWeights: number[] = [];
  const hasScorecardSignal = scorecardRatingNormalized !== null || recommendationNormalized !== null;

  const aiWeight = hasScorecardSignal ? 0.2 : 1;
  const scorecardRatingWeight = hasScorecardSignal ? 0.5 : 0;
  const recommendationWeight = hasScorecardSignal ? 0.3 : 0;

  if (aiFitScore !== null) {
    weightedParts.push(Math.max(0, Math.min(100, aiFitScore)) * aiWeight);
    weightedTotalWeights.push(aiWeight);
  }
  if (scorecardRatingNormalized !== null) {
    weightedParts.push(scorecardRatingNormalized * scorecardRatingWeight);
    weightedTotalWeights.push(scorecardRatingWeight);
  }
  if (recommendationNormalized !== null) {
    weightedParts.push(recommendationNormalized * recommendationWeight);
    weightedTotalWeights.push(recommendationWeight);
  }

  const totalWeight = weightedTotalWeights.reduce((acc, value) => acc + value, 0);
  if (totalWeight === 0) {
    return null;
  }

  const weightedScore = weightedParts.reduce((acc, value) => acc + value, 0) / totalWeight;
  return Math.round(weightedScore);
}

function recordApplicantStageMove(event: StageMoveEvent) {
  console.log("stage-move-event", event);
}

export default function ApplicantsSection({
  positionId,
  positionTitle,
  onApplicantStageMove = recordApplicantStageMove,
}: ApplicantsSectionProps) {
  const router = useRouter();
  const [applicants, setApplicants] = useState<Applicant[]>([]);
  const [draggedApplicantId, setDraggedApplicantId] = useState<string | null>(null);
  const [activeDropStageId, setActiveDropStageId] = useState<string | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [isUploadModalOpen, setIsUploadModalOpen] = useState(false);
  const [actionToast, setActionToast] = useState<string | null>(null);
  const [isDispositionModalOpen, setIsDispositionModalOpen] = useState(false);
  const [selectedDisposition, setSelectedDisposition] = useState<"hired" | "closed">("hired");
  const [pendingDispositionApplicantId, setPendingDispositionApplicantId] = useState<string | null>(null);
  const [firstName, setFirstName] = useState("");
  const [lastName, setLastName] = useState("");
  const [email, setEmail] = useState("");
  const [resumeFile, setResumeFile] = useState<File | null>(null);

  useEffect(() => {
    setIsLoading(true);
    const storedApplicants = readApplicantsFromStorage(positionId);
    const hasValidStageApplicant = storedApplicants.some((applicant) => stageIds.has(applicant.stageId));

    if (!hasValidStageApplicant) {
      const reseededApplicants = initialApplicantsByPosition[positionId] ?? [];
      writeApplicantsToStorage(positionId, reseededApplicants);
      setApplicants(reseededApplicants);
    } else {
      setApplicants(storedApplicants);
    }

    setIsLoading(false);
  }, [positionId]);

  const applicantsByStage = useMemo(() => {
    return stages.reduce<Record<string, Applicant[]>>((acc, stage) => {
      acc[stage.id] = applicants.filter((applicant) => applicant.stageId === stage.id);
      return acc;
    }, {});
  }, [applicants]);

  const topApplicant = useMemo(() => {
    let best: { applicant: Applicant; score: number } | null = null;

    for (const applicant of applicants) {
      const score = computeApplicantCompositeScore(applicant);
      if (score === null) {
        continue;
      }
      if (!best || score > best.score) {
        best = { applicant, score };
      }
    }

    return best;
  }, [applicants]);

  function showActionToast(message: string) {
    setActionToast(message);
    window.setTimeout(() => {
      setActionToast(null);
    }, 1800);
  }

  function getStageIndex(stageId: string) {
    return stages.findIndex((stage) => stage.id === stageId);
  }

  function isNextStageMove(fromStageId: string, toStageId: string) {
    return getStageIndex(toStageId) === getStageIndex(fromStageId) + 1;
  }

  function updateApplicantStage(applicantId: string, toStageId: string) {
    const applicant = applicants.find((item) => item.id === applicantId);
    if (!applicant || applicant.stageId === toStageId) {
      return null;
    }

    const fromStageId = applicant.stageId;
    const nextApplicants = applicants.map((item) =>
      item.id === applicantId ? { ...item, stageId: toStageId } : item
    );

    setApplicants(nextApplicants);
    writeApplicantsToStorage(positionId, nextApplicants);

    return {
      applicant,
      fromStageId,
      toStageId,
    };
  }

  function emitStageMovedEvent(args: { applicantId: string; applicantName: string; fromStageId: string; toStageId: string }) {
    const movedAt = new Date().toISOString();
    appendEventToStorage({
      eventType: "ApplicantStageMoved",
      traceId: positionId,
      payload: {
        streamCategory: "applicants_stream",
        streamId: `applicants:${positionId}`,
        positionId,
        applicantId: args.applicantId,
        applicantName: args.applicantName,
        fromStageId: args.fromStageId,
        toStageId: args.toStageId,
        movedAt,
      },
    });

    onApplicantStageMove({
      eventType: "applicant_stage_moved",
      applicantId: args.applicantId,
      applicantName: args.applicantName,
      fromStageId: args.fromStageId,
      toStageId: args.toStageId,
      movedAt,
    });
  }

  function startAIScreeningFromKanban(applicantId: string) {
    const applicant = applicants.find((item) => item.id === applicantId);
    if (!applicant || applicant.stageId !== "new_applied") {
      return;
    }
    router.push(`/applicants/${applicant.id}?positionId=${positionId}&openAIScreening=1`);
  }

  function startOfferLetterFromKanban(applicantId: string) {
    const applicant = applicants.find((item) => item.id === applicantId);
    if (!applicant || applicant.stageId !== "resume_review_screening") {
      return;
    }
    router.push(`/applicants/${applicant.id}?positionId=${positionId}&sendOffer=1`);
  }

  function openDispositionModal(applicantId: string) {
    setPendingDispositionApplicantId(applicantId);
    setSelectedDisposition("hired");
    setIsDispositionModalOpen(true);
  }

  function triggerNextStageAction(applicantId: string, toStageId: string) {
    const applicant = applicants.find((item) => item.id === applicantId);
    if (!applicant) {
      return;
    }

    if (!isNextStageMove(applicant.stageId, toStageId)) {
      showActionToast("Only moving to the next stage is allowed.");
      return;
    }

    if (applicant.stageId === "new_applied" && toStageId === "resume_review_screening") {
      startAIScreeningFromKanban(applicantId);
      return;
    }

    if (applicant.stageId === "resume_review_screening" && toStageId === "offer_letter_sent") {
      startOfferLetterFromKanban(applicantId);
      return;
    }

    if (applicant.stageId === "offer_letter_sent" && toStageId === "hired_or_closed") {
      openDispositionModal(applicantId);
      return;
    }
  }

  function handleFinalizeDisposition() {
    if (!pendingDispositionApplicantId) {
      return;
    }

    const applicant = applicants.find((item) => item.id === pendingDispositionApplicantId);
    if (!applicant || applicant.stageId !== "offer_letter_sent") {
      return;
    }

    const updated = updateApplicantStage(applicant.id, "hired_or_closed");
    if (!updated) {
      return;
    }

    emitStageMovedEvent({
      applicantId: updated.applicant.id,
      applicantName: updated.applicant.name,
      fromStageId: updated.fromStageId,
      toStageId: updated.toStageId,
    });
    appendEventToStorage({
      eventType: "ApplicantHireCloseDecisionMade",
      traceId: positionId,
      payload: {
        streamCategory: "manager_actions_stream",
        streamId: `manager-actions:${positionId}`,
        positionId,
        applicantId: applicant.id,
        applicantName: applicant.name,
        disposition: selectedDisposition,
        decidedAt: new Date().toISOString(),
      },
    });

    setIsDispositionModalOpen(false);
    setPendingDispositionApplicantId(null);
    showActionToast(
      selectedDisposition === "hired" ? "Applicant marked as hired" : "Applicant marked as closed"
    );
  }

  function uploadApplicant() {
    const trimmedFirstName = firstName.trim();
    const trimmedLastName = lastName.trim();
    const trimmedEmail = email.trim();

    if (!trimmedFirstName || !trimmedLastName || !trimmedEmail || !resumeFile) {
      return;
    }

    const applicantId = window.crypto?.randomUUID?.() ?? `app_${Date.now()}`;
    const applicantName = `${trimmedFirstName} ${trimmedLastName}`;
    const newApplicant: Applicant = {
      id: applicantId,
      name: applicantName,
      role: positionTitle,
      stageId: "new_applied",
      email: trimmedEmail,
      resumeFileName: resumeFile.name,
    };

    const nextApplicants = [...applicants, newApplicant];
    setApplicants(nextApplicants);
    writeApplicantsToStorage(positionId, nextApplicants);

    appendEventToStorage({
      eventType: "ApplicantDeclared",
      traceId: positionId,
      payload: {
        streamCategory: "applicants_stream",
        streamId: `applicants:${positionId}`,
        positionId,
        applicantId,
        applicantName,
        role: positionTitle,
        stageId: "new_applied",
        email: trimmedEmail,
        resumeFileName: resumeFile.name,
      },
    });

    setIsUploadModalOpen(false);
    setFirstName("");
    setLastName("");
    setEmail("");
    setResumeFile(null);

    router.push(`/applicants/${applicantId}?positionId=${positionId}&uploaded=1`);
  }

  const canUpload = firstName.trim() && lastName.trim() && email.trim() && resumeFile;

  return (
    <section className="px-6 pb-16 pt-10 md:px-12 lg:px-20">
      {actionToast && (
        <div className="fixed left-1/2 top-6 z-50 -translate-x-1/2 rounded-md bg-slate-700 px-4 py-3 text-sm font-semibold text-white shadow-lg">
          {actionToast}
        </div>
      )}

      <div className="flex flex-col gap-3 md:flex-row md:items-end md:justify-between">
        <div>
          <h2 className="text-4xl font-bold text-slate-900">Your Applicants</h2>
          <p className="mt-2 text-lg text-slate-600">
            Drag applicants across the hiring pipeline from application to final outcome.
          </p>
          {topApplicant && (
            <div className="mt-3 rounded-lg border border-emerald-200 bg-emerald-50 px-4 py-3">
              <p className="text-sm font-semibold uppercase tracking-wide text-emerald-800">
                Top Applicant Thus Far
              </p>
              <p className="mt-1 text-base font-semibold text-emerald-900">
                {topApplicant.applicant.name} ({topApplicant.score}/100)
              </p>
              <p className="text-sm text-emerald-800">
                {topApplicant.applicant.role} • {stageTitleById[topApplicant.applicant.stageId] ?? "Unknown Stage"}
              </p>
              <p className="mt-2 text-xs font-semibold text-emerald-800">
                Ranking model: 80% Scorecard (50% rating + 30% recommendation), 20% AI screening
              </p>
              <p className="mt-2 text-sm text-emerald-900">
                Scorecard: {recommendationLabel(topApplicant.applicant.scorecard?.recommendation)} • Rating:{" "}
                {topApplicant.applicant.scorecard?.rating ?? "Not submitted"}/5
              </p>
              {topApplicant.applicant.scorecard?.comments && (
                <p className="mt-1 line-clamp-2 text-sm text-emerald-800">
                  Notes: {topApplicant.applicant.scorecard.comments}
                </p>
              )}
            </div>
          )}
        </div>
        <button
          type="button"
          onClick={() => setIsUploadModalOpen(true)}
          className="h-11 rounded-md bg-slate-700 px-5 text-sm font-semibold text-white transition-colors hover:bg-slate-800"
        >
          New Applicant
        </button>
      </div>

      {isLoading ? (
        <div className="mt-8 grid gap-4 xl:grid-cols-5 md:grid-cols-2">
          {stages.map((stage) => (
            <div
              key={`applicants-skeleton-${stage.id}`}
              className="min-h-[380px] rounded-xl border border-slate-200 bg-white/70 p-4 animate-pulse"
            >
              <div className="h-7 w-2/3 rounded bg-slate-200" />
              <div className="mt-2 h-4 w-5/6 rounded bg-slate-200" />
              <div className="mt-4 space-y-3">
                <div className="rounded-lg border bg-white p-3">
                  <div className="h-5 w-3/4 rounded bg-slate-200" />
                  <div className="mt-2 h-4 w-1/2 rounded bg-slate-200" />
                </div>
                <div className="rounded-lg border bg-white p-3">
                  <div className="h-5 w-2/3 rounded bg-slate-200" />
                  <div className="mt-2 h-4 w-1/3 rounded bg-slate-200" />
                </div>
              </div>
            </div>
          ))}
        </div>
      ) : (
        <div className="mt-8 grid gap-4 xl:grid-cols-5 md:grid-cols-2">
          {stages.map((stage) => {
            const isDropActive = activeDropStageId === stage.id;
            const stageApplicants = applicantsByStage[stage.id] ?? [];

            return (
              <div
                key={stage.id}
                onDragOver={(event) => {
                  event.preventDefault();
                  setActiveDropStageId(stage.id);
                }}
                onDragLeave={() => {
                  setActiveDropStageId((current) => (current === stage.id ? null : current));
                }}
                onDrop={(event) => {
                  event.preventDefault();
                  const applicantId = event.dataTransfer.getData("text/applicant-id");
                  if (applicantId) {
                    triggerNextStageAction(applicantId, stage.id);
                  }
                  setDraggedApplicantId(null);
                  setActiveDropStageId(null);
                }}
                className={`min-h-[380px] rounded-xl border p-4 transition-colors ${
                  isDropActive ? "border-orange-400 bg-orange-50" : "border-slate-200 bg-white/70"
                }`}
              >
                <h3 className="text-2xl font-bold text-slate-800">{stage.title}</h3>
                <p className="mt-1 text-sm text-slate-500">{stage.subtitle}</p>

                <div className="mt-4 space-y-3">
                  {stageApplicants.map((applicant) => {
                    const isDragged = draggedApplicantId === applicant.id;

                    return (
                      <article
                        key={applicant.id}
                        draggable
                        onClick={() => {
                          router.push(`/applicants/${applicant.id}?positionId=${positionId}`);
                        }}
                        onKeyDown={(event) => {
                          if (event.key === "Enter" || event.key === " ") {
                            event.preventDefault();
                            router.push(`/applicants/${applicant.id}?positionId=${positionId}`);
                          }
                        }}
                        role="button"
                        tabIndex={0}
                        onDragStart={(event) => {
                          event.dataTransfer.setData("text/applicant-id", applicant.id);
                          event.dataTransfer.effectAllowed = "move";
                          setDraggedApplicantId(applicant.id);
                        }}
                        onDragEnd={() => {
                          setDraggedApplicantId(null);
                          setActiveDropStageId(null);
                        }}
                        className={`cursor-grab rounded-lg border bg-white p-3 shadow-sm transition-opacity active:cursor-grabbing ${
                          isDragged ? "opacity-60" : "opacity-100"
                        }`}
                      >
                        <p className="text-lg font-semibold text-slate-900">{applicant.name}</p>
                        <p className="text-sm text-slate-500">{applicant.role}</p>
                      </article>
                    );
                  })}

                  {stageApplicants.length === 0 && (
                    <div className="rounded-lg border border-dashed border-slate-300 p-4 text-sm text-slate-500">
                      Drop applicant here
                    </div>
                  )}
                </div>
              </div>
            );
          })}
        </div>
      )}

      {isDispositionModalOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/30 p-4 backdrop-blur-sm">
          <div className="w-full max-w-xl rounded-xl border border-slate-200 bg-white p-6 shadow-xl">
            <div className="flex items-center justify-between">
              <h3 className="text-2xl font-bold text-slate-900">Finalize Applicant Outcome</h3>
              <button
                type="button"
                onClick={() => {
                  setIsDispositionModalOpen(false);
                  setPendingDispositionApplicantId(null);
                }}
                className="text-sm font-semibold text-slate-500 underline underline-offset-4"
              >
                Close
              </button>
            </div>

            <p className="mt-3 text-slate-600">
              Choose whether this applicant should be marked as hired or closed.
            </p>

            <label className="mt-5 grid gap-1">
              <span className="text-sm font-medium text-slate-700">Outcome</span>
              <select
                value={selectedDisposition}
                onChange={(event) => setSelectedDisposition(event.target.value as "hired" | "closed")}
                className="rounded-md border border-slate-300 px-3 py-2 text-slate-800"
              >
                <option value="hired">Hired</option>
                <option value="closed">Closed</option>
              </select>
            </label>

            <div className="mt-6 flex justify-end">
              <button
                type="button"
                onClick={handleFinalizeDisposition}
                className="h-11 rounded-md bg-orange-500 px-5 text-sm font-semibold text-white transition-colors hover:bg-orange-600"
              >
                Confirm and Move
              </button>
            </div>
          </div>
        </div>
      )}

      {isUploadModalOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/30 p-4 backdrop-blur-sm">
          <div className="w-full max-w-2xl rounded-xl border border-slate-200 bg-white p-6 shadow-xl">
            <div className="flex items-center justify-between">
              <h3 className="text-2xl font-bold text-slate-900">Upload New Applicant</h3>
              <button
                type="button"
                onClick={() => setIsUploadModalOpen(false)}
                className="text-sm font-semibold text-slate-500 underline underline-offset-4"
              >
                Close
              </button>
            </div>

            <div className="mt-6 grid gap-4 md:grid-cols-2">
              <label className="grid gap-1">
                <span className="text-sm font-medium text-slate-700">Applicant First Name</span>
                <input
                  value={firstName}
                  onChange={(event) => setFirstName(event.target.value)}
                  className="rounded-md border border-slate-300 px-3 py-2 text-slate-800"
                />
              </label>
              <label className="grid gap-1">
                <span className="text-sm font-medium text-slate-700">Applicant Last Name</span>
                <input
                  value={lastName}
                  onChange={(event) => setLastName(event.target.value)}
                  className="rounded-md border border-slate-300 px-3 py-2 text-slate-800"
                />
              </label>
            </div>

            <label className="mt-4 grid gap-1">
              <span className="text-sm font-medium text-slate-700">Email</span>
              <input
                type="email"
                value={email}
                onChange={(event) => setEmail(event.target.value)}
                className="rounded-md border border-slate-300 px-3 py-2 text-slate-800"
              />
            </label>

            <div className="mt-4">
              <p className="text-sm font-medium text-slate-700">Resume</p>
              <label
                onDragOver={(event) => event.preventDefault()}
                onDrop={(event) => {
                  event.preventDefault();
                  const file = event.dataTransfer.files?.[0];
                  if (file) {
                    setResumeFile(file);
                  }
                }}
                className="mt-1 flex min-h-32 cursor-pointer items-center justify-center rounded-lg border-2 border-dashed border-slate-300 bg-slate-50 p-4 text-center text-sm text-slate-600"
              >
                <input
                  type="file"
                  accept=".pdf,.doc,.docx"
                  className="hidden"
                  onChange={(event) => {
                    const file = event.target.files?.[0];
                    if (file) {
                      setResumeFile(file);
                    }
                  }}
                />
                {resumeFile ? `Selected: ${resumeFile.name}` : "Drag and drop resume here, or click to browse"}
              </label>
            </div>

            <div className="mt-6 flex justify-end">
              <button
                type="button"
                onClick={uploadApplicant}
                disabled={!canUpload}
                className="h-11 rounded-md bg-orange-500 px-5 text-sm font-semibold text-white transition-colors hover:bg-orange-600 disabled:cursor-not-allowed disabled:bg-slate-300"
              >
                Upload Applicant
              </button>
            </div>
          </div>
        </div>
      )}
    </section>
  );
}
