/**
 * Job Seeker Jobs Page - Wired to real backend APIs
 * Endpoints:
 *   GET /api/jobseeker/jobs - List available jobs from companies
 *   POST /api/jobseeker/jobs/:id/apply - Apply for a job
 *   POST /api/ai/generate-cover-letter - AI cover letter generation
 *   Custom data: saved_jobs - Bookmarked jobs stored in profile
 */
import { For, Show, createMemo, createSignal, onMount } from "solid-js";
import { Sparkles, Loader } from "lucide-solid";
import { BTN_GHOST, BTN_PRIMARY, CARD, INPUT } from "~/components/DashboardShell";
import { readJobSeekerProfile, updateJobSeekerCustomData } from "~/lib/job-seeker-custom-data";

const API = "";

type JobItem = {
  id: string;
  title?: string;
  company_name?: string;
  location?: string;
  salary_min?: number | null;
  salary_max?: number | null;
  employment_type?: string;
  status?: string;
  description?: string | null;
  category?: string | null;
  skills?: string[] | null;
  created_at?: string;
};

type SortKey = "newest" | "salary_desc" | "salary_asc" | "title_asc";

type SavedJob = {
  id: string;
  title: string;
  company?: string;
  location?: string;
  salary?: string;
  saved_at: string;
};

async function apiFetch(path: string, opts?: RequestInit) {
  const token =
    typeof window !== "undefined"
      ? window.sessionStorage.getItem("nxtgauge_access_token") || ""
      : "";
  return fetch(`${API}${path}`, {
    ...opts,
    credentials: "include",
    headers: {
      "Content-Type": "application/json",
      ...(token ? { Authorization: `Bearer ${token}` } : {}),
      ...(opts?.headers ?? {}),
    },
  });
}

function rowTags(row: JobItem): string[] {
  const tags = new Set<string>();
  if (row.category) tags.add(String(row.category));
  if (Array.isArray(row.skills)) {
    for (const skill of row.skills) {
      const val = String(skill || "").trim();
      if (val) tags.add(val);
    }
  }
  return Array.from(tags);
}

function formatSalary(job: JobItem): string {
  const min = Number(job.salary_min || 0);
  const max = Number(job.salary_max || 0);
  if (!min && !max) return "";
  if (min && max) return `${min} - ${max}`;
  return String(min || max || "");
}

function toSavedJobs(value: unknown): SavedJob[] {
  if (!Array.isArray(value)) return [];
  return value
    .map((item) => {
      const row = item as Record<string, unknown>;
      const id = String(row?.id || "").trim();
      if (!id) return null;
      return {
        id,
        title: String(row?.title || "Untitled Job"),
        company: String(row?.company || row?.company_name || ""),
        location: String(row?.location || ""),
        salary: String(row?.salary || ""),
        saved_at: String(row?.saved_at || new Date().toISOString()),
      };
    })
    .filter(Boolean) as SavedJob[];
}

export default function JobSeekerJobsPage() {
  const [rows, setRows] = createSignal<JobItem[]>([]);
  const [savedJobs, setSavedJobs] = createSignal<SavedJob[]>([]);
  const [loading, setLoading] = createSignal(true);
  const [busyId, setBusyId] = createSignal<string | null>(null);
  const [search, setSearch] = createSignal("");
  const [sortBy, setSortBy] = createSignal<SortKey>("newest");
  const [activeTag, setActiveTag] = createSignal("");
  const [msg, setMsg] = createSignal("");
  const [err, setErr] = createSignal("");
  const [generatingCover, setGeneratingCover] = createSignal<string | null>(null);
  // Per-job cover letter map: jobId → { text, expanded }
  const [coverLetters, setCoverLetters] = createSignal<Record<string, { text: string; expanded: boolean }>>({});
  const [aiRemaining, setAiRemaining] = createSignal(5);
  const [aiLimit, setAiLimit] = createSignal(5);

  const getCoverLetter = (jobId: string) => coverLetters()[jobId] ?? null;
  const setCoverLetter = (jobId: string, text: string) =>
    setCoverLetters((prev) => ({ ...prev, [jobId]: { text, expanded: true } }));
  const updateCoverLetterText = (jobId: string, text: string) =>
    setCoverLetters((prev) => ({
      ...prev,
      [jobId]: { ...(prev[jobId] ?? { text: "", expanded: true }), text },
    }));
  const toggleExpanded = (jobId: string) =>
    setCoverLetters((prev) => ({
      ...prev,
      [jobId]: { ...(prev[jobId] ?? { text: "", expanded: false }), expanded: !prev[jobId]?.expanded },
    }));
  const clearCoverLetter = (jobId: string) =>
    setCoverLetters((prev) => {
      const next = { ...prev };
      delete next[jobId];
      return next;
    });

  const availableTags = createMemo(() => {
    const tags = new Set<string>();
    for (const row of rows()) {
      for (const tag of rowTags(row)) tags.add(tag);
    }
    return Array.from(tags).sort((a, b) => a.localeCompare(b));
  });

  const loadRows = async () => {
    setLoading(true);
    setErr("");
    try {
      const res = await apiFetch("/api/jobseeker/jobs?page=1&limit=100");
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        setErr(data.error || data.message || "Failed to load jobs.");
        setRows([]);
        return;
      }
      setRows(Array.isArray(data?.data) ? data.data : []);
    } catch {
      setErr("Network error while loading jobs.");
      setRows([]);
    } finally {
      setLoading(false);
    }
  };

  const loadSavedJobs = async () => {
    try {
      const profile = await readJobSeekerProfile();
      setSavedJobs(toSavedJobs(profile?.custom_data?.saved_jobs));
    } catch {
      // non-blocking
      setSavedJobs([]);
    }
  };

  onMount(() => {
    void loadRows();
    void loadSavedJobs();
  });

  const applyJob = async (jobId: string) => {
    setBusyId(jobId);
    setMsg("");
    setErr("");
    const letter = getCoverLetter(jobId)?.text || undefined;
    try {
      const res = await apiFetch(`/api/jobseeker/jobs/${jobId}/apply`, {
        method: "POST",
        body: JSON.stringify({
          cover_note: letter || undefined,
        }),
      });
      const data = await res.json().catch(() => ({}));
      if (!res.ok) {
        if (res.status === 409) {
          setErr("You have already applied to this job.");
        } else if (res.status === 400) {
          setErr(data.error || data.message || "Invalid application — check your profile is complete.");
        } else {
          setErr(data.error || data.message || "Failed to apply for job.");
        }
        return;
      }
      setMsg("Application submitted successfully.");
      clearCoverLetter(jobId);
    } catch {
      setErr("Network error while applying.");
    } finally {
      setBusyId(null);
    }
  };

  const generateCoverLetter = async (job: JobItem) => {
    if (aiRemaining() <= 0) {
      setErr("Daily AI generation limit reached. Upgrade to AI Pack for more.");
      return;
    }
    setGeneratingCover(job.id);
    setErr("");
    try {
      const token = window.sessionStorage.getItem("nxtgauge_access_token") || "";
      const res = await fetch(`${API}/api/ai/generate-cover-letter`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
        body: JSON.stringify({
          job_title: job.title || "this position",
          company_name: job.company_name || undefined,
          job_description: job.description || undefined,
        }),
      });

      if (res.status === 429) {
        setErr("Daily AI generation limit reached. Upgrade to AI Pack for more.");
        return;
      }

      const data = await res.json();
      if (res.ok && data.cover_letter) {
        setCoverLetter(job.id, data.cover_letter);
        setAiRemaining(data.remaining_today ?? aiRemaining() - 1);
        setAiLimit(data.daily_limit ?? aiLimit());
      } else {
        setErr(data.error || "Failed to generate cover letter");
      }
    } catch {
      setErr("Network error during cover letter generation");
    } finally {
      setGeneratingCover(null);
    }
  };

  const isSaved = (jobId: string) => savedJobs().some((row) => row.id === jobId);

  const toggleSave = async (job: JobItem) => {
    setBusyId(job.id);
    setMsg("");
    setErr("");
    const existing = savedJobs();
    const next = isSaved(job.id)
      ? existing.filter((row) => row.id !== job.id)
      : [
          ...existing,
          {
            id: job.id,
            title: String(job.title || "Untitled Job"),
            company: String(job.company_name || ""),
            location: String(job.location || ""),
            salary: formatSalary(job),
            saved_at: new Date().toISOString(),
          },
        ];
    try {
      await updateJobSeekerCustomData((current) => ({ ...current, saved_jobs: next }));
      setSavedJobs(next);
      setMsg(isSaved(job.id) ? "Job removed from saved list." : "Job saved for later.");
    } catch (e: any) {
      setErr(e?.message || "Failed to update saved jobs.");
    } finally {
      setBusyId(null);
    }
  };

  const filtered = () => {
    const q = search().trim().toLowerCase();
    const tag = activeTag().trim().toLowerCase();
    const next = rows().filter((r) => {
      const tags = rowTags(r);
      const matchesTag = !tag || tags.some((t) => t.toLowerCase() === tag);
      if (!matchesTag) return false;
      if (!q) return true;
      return (
        String(r.title || "").toLowerCase().includes(q) ||
        String(r.company_name || "").toLowerCase().includes(q) ||
        String(r.location || "").toLowerCase().includes(q) ||
        String(r.category || "").toLowerCase().includes(q) ||
        tags.some((t) => t.toLowerCase().includes(q))
      );
    });
    next.sort((a, b) => {
      if (sortBy() === "salary_desc") return Number(b.salary_max || b.salary_min || 0) - Number(a.salary_max || a.salary_min || 0);
      if (sortBy() === "salary_asc") return Number(a.salary_min || a.salary_max || 0) - Number(b.salary_min || b.salary_max || 0);
      if (sortBy() === "title_asc") return String(a.title || "").localeCompare(String(b.title || ""));
      return new Date(String(b.created_at || 0)).getTime() - new Date(String(a.created_at || 0)).getTime();
    });
    return next;
  };

  return (
    <div style={{ display: "grid", gap: "14px", "max-width": "980px" }}>
      <div style={CARD}>
        <p style={{ margin: "0", "font-size": "18px", "font-weight": "800", color: "#111827" }}>
          Jobs
        </p>
        <p style={{ margin: "4px 0 0", "font-size": "13px", color: "#6B7280" }}>
          Explore approved job postings and apply directly.
        </p>
      </div>

      <Show when={msg()}>
        <div
          style={{
            ...CARD,
            border: "1px solid #BBF7D0",
            background: "#ECFDF5",
            padding: "12px 14px",
            color: "#065F46",
            "font-size": "13px",
            "font-weight": "600",
          }}
        >
          {msg()}
        </div>
      </Show>
      <Show when={err()}>
        <div
          style={{
            ...CARD,
            border: "1px solid #FECACA",
            background: "#FEF2F2",
            padding: "12px 14px",
            color: "#B91C1C",
            "font-size": "13px",
            "font-weight": "600",
          }}
        >
          {err()}
        </div>
      </Show>

      <div style={{ ...CARD, display: "grid", gap: "10px" }}>
        <div style={{ display: "grid", "grid-template-columns": "1fr 180px auto", gap: "10px", "align-items": "center" }}>
          <input
            value={search()}
            onInput={(e) => setSearch(e.currentTarget.value)}
            style={INPUT}
            placeholder="Search jobs, company, location, tags"
          />
          <select value={sortBy()} onChange={(e) => setSortBy(e.currentTarget.value as SortKey)} style={INPUT}>
            <option value="newest">Sort: Newest</option>
            <option value="salary_desc">Salary High to Low</option>
            <option value="salary_asc">Salary Low to High</option>
            <option value="title_asc">Title A-Z</option>
          </select>
          <button type="button" onClick={loadRows} style={BTN_GHOST}>
            Refresh
          </button>
        </div>
        <Show when={availableTags().length > 0}>
          <div style={{ display: "flex", gap: "6px", "flex-wrap": "wrap" }}>
            <button
              type="button"
              onClick={() => setActiveTag("")}
              style={{ ...BTN_GHOST, height: "28px", padding: "0 10px", "font-size": "11px", ...(activeTag() ? {} : { border: "1px solid #0D0D2A", color: "#0D0D2A" }) }}
            >
              All Tags
            </button>
            <For each={availableTags()}>
              {(tag) => (
                <button
                  type="button"
                  onClick={() => setActiveTag(tag)}
                  style={{ ...BTN_GHOST, height: "28px", padding: "0 10px", "font-size": "11px", ...(activeTag() === tag ? { border: "1px solid #0D0D2A", color: "#0D0D2A" } : {}) }}
                >
                  {tag}
                </button>
              )}
            </For>
          </div>
        </Show>
      </div>

      <Show when={loading()}>
        <div style={{ ...CARD, "text-align": "center", color: "#9CA3AF" }}>Loading jobs...</div>
      </Show>
      <Show when={!loading() && filtered().length === 0}>
        <div style={{ ...CARD, "text-align": "center", color: "#6B7280" }}>No jobs found.</div>
      </Show>

      <Show when={!loading() && filtered().length > 0}>
        <div style={{ display: "grid", gap: "10px" }}>
          <For each={filtered()}>
            {(row) => (
              <div style={{ ...CARD, padding: "14px" }}>
                <div
                  style={{
                    display: "flex",
                    "justify-content": "space-between",
                    gap: "10px",
                    "flex-wrap": "wrap",
                  }}
                >
                  <div>
                    <p
                      style={{
                        margin: "0",
                        "font-size": "16px",
                        "font-weight": "800",
                        color: "#111827",
                      }}
                    >
                      {row.title || "Untitled Job"}
                    </p>
                    <p style={{ margin: "4px 0 0", "font-size": "12px", color: "#6B7280" }}>
                      {row.company_name || "Company"} {row.location ? `• ${row.location}` : ""}{" "}
                      {row.employment_type ? `• ${row.employment_type}` : ""}
                    </p>
                  </div>
                  <span
                    style={{
                      display: "inline-flex",
                      height: "24px",
                      "align-items": "center",
                      padding: "0 10px",
                      "border-radius": "999px",
                      background: "#EEF2FF",
                      color: "#3730A3",
                      "font-size": "11px",
                      "font-weight": "700",
                    }}
                  >
                    {String(row.status || "OPEN").replace(/_/g, " ")}
                  </span>
                </div>
                <p style={{ margin: "8px 0 0", "font-size": "13px", color: "#374151" }}>
                  {row.description || "No description provided."}
                </p>
                <Show when={rowTags(row).length > 0}>
                  <div style={{ display: "flex", gap: "6px", "flex-wrap": "wrap", "margin-top": "8px" }}>
                    <For each={rowTags(row).slice(0, 6)}>
                      {(tag) => (
                        <span style={{ height: "22px", display: "inline-flex", "align-items": "center", padding: "0 8px", "border-radius": "999px", border: "1px solid #E5E7EB", background: "#F9FAFB", "font-size": "11px", color: "#374151" }}>{tag}</span>
                      )}
                    </For>
                  </div>
                </Show>
                <p
                  style={{
                    margin: "8px 0 0",
                    "font-size": "12px",
                    color: "#111827",
                    "font-weight": "700",
                  }}
                >
                  Salary: {formatSalary(row) || "Not specified"}
                </p>
                <div
                  style={{
                    display: "flex",
                    "justify-content": "flex-end",
                    gap: "8px",
                    "margin-top": "10px",
                  }}
                >
                  <button
                    type="button"
                    onClick={() => void toggleSave(row)}
                    disabled={busyId() === row.id || generatingCover() === row.id}
                    style={{
                      ...BTN_GHOST,
                      height: "32px",
                      "font-size": "12px",
                      padding: "0 12px",
                      opacity: busyId() === row.id || generatingCover() === row.id ? "0.7" : "1",
                    }}
                  >
                    {busyId() === row.id ? "Updating..." : isSaved(row.id) ? "Unsave" : "Save"}
                  </button>
                  <button
                    type="button"
                    onClick={() => generateCoverLetter(row)}
                    disabled={generatingCover() === row.id || busyId() === row.id || aiRemaining() <= 0}
                    style={{
                      ...BTN_GHOST,
                      height: "32px",
                      "font-size": "12px",
                      padding: "0 12px",
                      "border-color": "#FF5E13",
                      color: "#FF5E13",
                      display: "inline-flex",
                      "align-items": "center",
                      gap: "5px",
                      opacity: generatingCover() === row.id || busyId() === row.id || aiRemaining() <= 0 ? "0.7" : "1",
                    }}
                    title={aiRemaining() <= 0 ? "Daily AI limit reached" : "Generate cover letter with AI"}
                  >
                    <Show when={generatingCover() === row.id} fallback={<Sparkles size={14} />}>
                      <Loader size={14} style={{ animation: "spin 1s linear infinite" }} />
                    </Show>
                    {generatingCover() === row.id ? "Generating..." : getCoverLetter(row.id) ? "Regenerate" : "Cover Letter"}
                  </button>
                  <button
                    type="button"
                    onClick={() => void applyJob(row.id)}
                    disabled={busyId() === row.id}
                    style={{
                      ...BTN_PRIMARY,
                      height: "32px",
                      "font-size": "12px",
                      padding: "0 12px",
                      opacity: busyId() === row.id ? "0.7" : "1",
                    }}
                  >
                    {busyId() === row.id ? "Applying..." : getCoverLetter(row.id) ? "Apply with Cover Letter" : "Apply"}
                  </button>
                </div>

                {/* Per-job cover letter panel */}
                <Show when={getCoverLetter(row.id)}>
                  <div style={{
                    "margin-top": "10px",
                    border: "1px solid #FFEDD5",
                    "border-radius": "8px",
                    overflow: "hidden",
                  }}>
                    {/* Panel header */}
                    <div style={{
                      display: "flex",
                      "align-items": "center",
                      "justify-content": "space-between",
                      padding: "8px 12px",
                      background: "#FFF7ED",
                      "border-bottom": getCoverLetter(row.id)?.expanded ? "1px solid #FFEDD5" : "none",
                    }}>
                      <div style={{ display: "flex", "align-items": "center", gap: "6px" }}>
                        <Sparkles size={13} style={{ color: "#EA580C" }} />
                        <span style={{ "font-size": "12px", "font-weight": "700", color: "#C2410C" }}>
                          AI Cover Letter
                        </span>
                        <span style={{
                          "font-size": "10px",
                          background: "#FFEDD5",
                          color: "#9A3412",
                          padding: "1px 6px",
                          "border-radius": "999px",
                          "font-weight": "600",
                        }}>
                          {aiRemaining()}/{aiLimit()} left today
                        </span>
                      </div>
                      <div style={{ display: "flex", gap: "8px", "align-items": "center" }}>
                        <button
                          type="button"
                          onClick={() => toggleExpanded(row.id)}
                          style={{
                            background: "none", border: "none",
                            "font-size": "11px", color: "#EA580C",
                            cursor: "pointer", padding: "0", "font-weight": "600",
                          }}
                        >
                          {getCoverLetter(row.id)?.expanded ? "▲ Collapse" : "▼ Expand"}
                        </button>
                        <button
                          type="button"
                          onClick={() => clearCoverLetter(row.id)}
                          style={{
                            background: "none", border: "none",
                            "font-size": "11px", color: "#9CA3AF",
                            cursor: "pointer", padding: "0",
                          }}
                        >
                          ✕ Clear
                        </button>
                      </div>
                    </div>

                    {/* Editable textarea — only when expanded */}
                    <Show when={getCoverLetter(row.id)?.expanded}>
                      <div style={{ background: "#FFFBF7", padding: "10px 12px" }}>
                        <p style={{
                          margin: "0 0 6px",
                          "font-size": "11px",
                          color: "#92400E",
                        }}>
                          Edit before submitting — changes only affect this application.
                        </p>
                        <textarea
                          value={getCoverLetter(row.id)?.text ?? ""}
                          onInput={(e) => updateCoverLetterText(row.id, e.currentTarget.value)}
                          rows={10}
                          style={{
                            width: "100%",
                            "box-sizing": "border-box",
                            padding: "10px",
                            border: "1px solid #FED7AA",
                            "border-radius": "6px",
                            "font-size": "12px",
                            "font-family": "inherit",
                            color: "#1C1917",
                            background: "#FFFFFF",
                            resize: "vertical",
                            "line-height": "1.6",
                            outline: "none",
                          }}
                        />
                      </div>
                    </Show>
                  </div>
                </Show>
              </div>
            )}
          </For>
        </div>
      </Show>

      <style>{`
        @keyframes spin {
          from { transform: rotate(0deg); }
          to { transform: rotate(360deg); }
        }
      `}</style>
    </div>
  );
}
