import React, { useEffect, useMemo, useState } from "react";
import { useLocation, useNavigate } from "react-router-dom";

import {
  Box,
  Button,
  Checkbox,
  Chip,
  Collapse,
  FormControl,
  FormControlLabel,
  IconButton,
  InputAdornment,
  InputLabel,
  Menu,
  MenuItem,
  Paper,
  Select,
  Table,
  TableBody,
  TableCell,
  TableHead,
  TablePagination,
  TableRow,
  TableSortLabel,
  TextField,
  Tooltip,
  Typography,
} from "@mui/material";
import { alpha, useTheme } from "@mui/material/styles";
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
import EditOutlinedIcon from "@mui/icons-material/EditOutlined";
import LaunchIcon from "@mui/icons-material/Launch";
import KeyboardArrowDownIcon from "@mui/icons-material/KeyboardArrowDown";
import KeyboardArrowUpIcon from "@mui/icons-material/KeyboardArrowUp";
import RestoreFromTrashOutlinedIcon from "@mui/icons-material/RestoreFromTrashOutlined";
import MoreHorizIcon from "@mui/icons-material/MoreHoriz";
import ViewColumnIcon from "@mui/icons-material/ViewColumn";
import SearchIcon from "@mui/icons-material/Search";

import { api } from "../api";
import { useCompanies } from "../hooks/useCompanies";
import { useDebouncedValue } from "../hooks/useDebouncedValue";
import JobDetailsDialog from "./JobDetailsDialog";
import EditJobDialog from "./EditJobDialog";
import { useToast } from "../toast";
import SavedViewsMenu, { SavedViewParams } from "./SavedViewsMenu";

interface JobApplication {
  id: number;
  jobTitle: string;
  status: string;
  dateApplied: string;
  daysSince: number;
  jobUrl?: string | null;
  notes?: string | null;
  location?: string | null;
  salary?: string | null;
  tags?: string | null;
  description?: string | null;
  isDeleted?: boolean;
  company: { name: string };
  companyId?: number;
  needsFollowUp?: boolean;
  followUpReason?: string | null;
  shortSummary?: string | null;
  fullSummary?: string | null;
}

interface PagedResult<T> {
  items: T[];
  total: number;
  page: number;
  pageSize: number;
}

export type JobTableColumns = {
  status: boolean;
  dateApplied: boolean;
  daysSince: boolean;
  jobUrl: boolean;
};

interface Props {
  refreshToken: number;
  pageSize: 15 | 20 | 25;
  onPageSizeChange: (n: 15 | 20 | 25) => void;
  columns: JobTableColumns;
  onColumnsChange: (next: JobTableColumns) => void;
  mode?: "jobs" | "trash";
}

function normalizeStatus(status: string): string {
  return status === "Interviewing" ? "Interview" : status;
}

function parseTags(raw?: string | null): string[] {
  if (!raw) return [];
  try {
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parsed.filter((x) => typeof x === "string") : [];
  } catch {
    return raw.split(/[,;\n]/).map((x) => x.trim()).filter(Boolean);
  }
}

function statusTone(status: string): string {
  switch (normalizeStatus(status)) {
    case "Offer":
      return "success";
    case "Rejected":
      return "error";
    case "Waiting":
    case "Ghosted":
      return "warning";
    case "Interview":
      return "info";
    default:
      return "primary";
  }
}

export default function JobTable({ refreshToken, pageSize, onPageSizeChange, columns, onColumnsChange, mode = "jobs" }: Props) {
  const theme = useTheme();
  const { toast } = useToast();
  const location = useLocation();
  const navigate = useNavigate();
  const [jobs, setJobs] = useState<JobApplication[]>([]);
  const [total, setTotal] = useState(0);
  const [page, setPage] = useState(0);
  const [expanded, setExpanded] = useState<number[]>([]);
  const [selectedIds, setSelectedIds] = useState<number[]>([]);
  const [search, setSearch] = useState("");
  const debouncedSearch = useDebouncedValue(search, 250);
  const [includeDeleted, setIncludeDeleted] = useState(mode === "trash");
  const [columnsAnchor, setColumnsAnchor] = useState<null | HTMLElement>(null);
  const [statusFilter, setStatusFilter] = useState("All");
  const [locationFilter, setLocationFilter] = useState("");
  const debouncedLocation = useDebouncedValue(locationFilter, 250);
  const [needsFollowUpOnly, setNeedsFollowUpOnly] = useState(false);
  const { companies } = useCompanies();
  const [companyFilterId, setCompanyFilterId] = useState<number | "All">("All");
  const [detailsJobId, setDetailsJobId] = useState<number | null>(null);
  const [editJobId, setEditJobId] = useState<number | null>(null);
  const [reloadToken, setReloadToken] = useState(0);
  const [statusAnchor, setStatusAnchor] = useState<null | HTMLElement>(null);
  const [statusJobId, setStatusJobId] = useState<number | null>(null);
  const [sortBy, setSortBy] = useState<"dateApplied" | "company" | "jobTitle" | "status" | "daysSince" | "location">("dateApplied");
  const [sortDir, setSortDir] = useState<"asc" | "desc">("desc");

  const params = useMemo(() => ({
    page: page + 1,
    pageSize,
    q: debouncedSearch.trim() || undefined,
    status: statusFilter !== "All" ? statusFilter : undefined,
    companyId: companyFilterId === "All" ? undefined : companyFilterId,
    location: debouncedLocation.trim() || undefined,
    includeDeleted,
    deletedOnly: mode === "trash" ? true : undefined,
    sortBy,
    sortDir,
    needsFollowUp: needsFollowUpOnly ? true : undefined,
  }), [page, pageSize, debouncedSearch, statusFilter, companyFilterId, debouncedLocation, includeDeleted, mode, sortBy, sortDir, needsFollowUpOnly]);

  useEffect(() => {
    api.get<PagedResult<JobApplication>>("/jobapplications", { params }).then((r) => {
      setJobs(r.data.items);
      setTotal(r.data.total);
      setSelectedIds([]);
    });
  }, [params, refreshToken, reloadToken]);

  useEffect(() => {
    const paramsSearch = new URLSearchParams(location.search);
    const openId = Number(paramsSearch.get("open") || 0);
    if (!openId || jobs.length === 0) return;
    const job = jobs.find((j) => j.id === openId);
    if (!job) return;
    setDetailsJobId(openId);
    paramsSearch.delete("open");
    navigate({ pathname: location.pathname, search: paramsSearch.toString() ? `?${paramsSearch.toString()}` : "" }, { replace: true });
  }, [jobs, location.pathname, location.search, navigate]);

  const requestSort = (key: typeof sortBy) => {
    if (sortBy === key) setSortDir((d) => (d === "asc" ? "desc" : "asc"));
    else {
      setSortBy(key);
      setSortDir("asc");
    }
    setPage(0);
  };

  const toggleExpanded = (id: number) => {
    setExpanded((prev) => (prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id]));
  };

  const selectedAllOnPage = jobs.length > 0 && jobs.every((job) => selectedIds.includes(job.id));

  const toggleSelectAll = (checked: boolean) => {
    setSelectedIds(checked ? jobs.map((job) => job.id) : []);
  };

  const toggleSelected = (id: number, checked: boolean) => {
    setSelectedIds((prev) => checked ? [...prev, id] : prev.filter((x) => x !== id));
  };

  const confirmDelete = (jobsToDelete: JobApplication[]) => {
    if (jobsToDelete.length === 0) return false;
    if (jobsToDelete.length === 1) {
      const job = jobsToDelete[0];
      return window.confirm(`Move "${job.jobTitle}" at ${job.company?.name ?? "this company"} to trash?`);
    }
    return window.confirm(`Move ${jobsToDelete.length} selected jobs to trash?`);
  };

  const softDelete = async (job: JobApplication) => {
    if (!confirmDelete([job])) return;
    try {
      await api.delete(`/jobapplications/${job.id}`);
      toast("Job moved to trash.", "success", { label: "Undo", onClick: () => { void restore(job.id); } });
      setReloadToken((t) => t + 1);
    } catch {
      toast("Failed to delete job.", "error");
    }
  };

  const restore = async (id: number) => {
    try {
      await api.post(`/jobapplications/${id}/restore`);
      toast("Job restored.", "success");
      setReloadToken((t) => t + 1);
    } catch {
      toast("Failed to restore job.", "error");
    }
  };

  const setStatusQuick = async (id: number, status: string) => {
    try {
      await api.patch(`/jobapplications/${id}/status`, { status });
      toast(`Status set to ${status}.`, "success");
      setReloadToken((t) => t + 1);
    } catch {
      toast("Failed to update status.", "error");
    }
  };

  const runBulkAction = async (action: "delete" | "restore" | "status", value?: string) => {
    if (selectedIds.length === 0) return;
    const selectedJobs = jobs.filter((job) => selectedIds.includes(job.id));
    if (action === "delete" && !confirmDelete(selectedJobs)) return;
    try {
      await Promise.all(selectedIds.map((id) => {
        if (action === "delete") return api.delete(`/jobapplications/${id}`);
        if (action === "restore") return api.post(`/jobapplications/${id}/restore`);
        return api.patch(`/jobapplications/${id}/status`, { status: value });
      }));
      toast(`Updated ${selectedIds.length} jobs.`, "success");
      setReloadToken((t) => t + 1);
      setSelectedIds([]);
    } catch {
      toast("Bulk action failed.", "error");
    }
  };

  const generateOverview = (job: JobApplication) => {
    if (job.shortSummary) return job.shortSummary;
    const src = (job.description || job.notes || "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
    return src.length > 220 ? `${src.slice(0, 220)}...` : src;
  };

  return (
    <Box>
      <Box sx={{ display: "flex", gap: 2, alignItems: "center", justifyContent: "space-between", mt: 2, flexWrap: "wrap" }}>
        <TextField
          label="Search"
          value={search}
          onChange={(e) => { setSearch(e.target.value); setPage(0); }}
          placeholder="Title, company, notes, messages"
          size="small"
          InputProps={{ startAdornment: <InputAdornment position="start"><SearchIcon fontSize="small" /></InputAdornment> }}
          sx={{ minWidth: 320, flex: "1 1 320px" }}
        />

        <FormControl sx={{ minWidth: 160 }} size="small">
          <InputLabel>Status</InputLabel>
          <Select value={statusFilter} label="Status" onChange={(e) => { setStatusFilter(e.target.value); setPage(0); }}>
            {["All", "Applied", "Waiting", "Interview", "Offer", "Rejected", "Ghosted"].map((s) => <MenuItem key={s} value={s}>{s}</MenuItem>)}
          </Select>
        </FormControl>

        <FormControl sx={{ minWidth: 220 }} size="small">
          <InputLabel>Company</InputLabel>
          <Select value={companyFilterId} label="Company" onChange={(e) => { setCompanyFilterId(e.target.value as any); setPage(0); }}>
            <MenuItem value="All">All</MenuItem>
            {companies.map((c) => <MenuItem key={c.id} value={c.id}>{c.name}</MenuItem>)}
          </Select>
        </FormControl>

        <TextField label="Location" value={locationFilter} onChange={(e) => { setLocationFilter(e.target.value); setPage(0); }} sx={{ minWidth: 200, flex: "1 1 200px" }} />

        <Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }}>
          {mode === "jobs" ? <FormControlLabel control={<Checkbox checked={needsFollowUpOnly} onChange={(e) => { setNeedsFollowUpOnly(e.target.checked); setPage(0); }} />} label="Needs follow-up" /> : null}
          {mode === "jobs" ? <FormControlLabel control={<Checkbox checked={includeDeleted} onChange={(e) => { setIncludeDeleted(e.target.checked); setPage(0); }} />} label="Show deleted" /> : null}
          <SavedViewsMenu current={{ q: search.trim() || undefined, status: statusFilter !== "All" ? statusFilter : undefined, companyId: companyFilterId === "All" ? undefined : (companyFilterId as number), location: locationFilter.trim() || undefined, needsFollowUp: needsFollowUpOnly ? true : undefined }} onApply={(p: SavedViewParams) => { setSearch(p.q ?? ""); setStatusFilter(p.status ?? "All"); setCompanyFilterId(p.companyId ?? "All"); setLocationFilter(p.location ?? ""); setNeedsFollowUpOnly(Boolean(p.needsFollowUp)); setPage(0); }} />
          <Tooltip title="Columns"><IconButton onClick={(e) => setColumnsAnchor(e.currentTarget)}><ViewColumnIcon /></IconButton></Tooltip>
        </Box>
      </Box>

      {selectedIds.length > 0 ? (
        <Paper sx={{ mt: 2, p: 1.5, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 2, flexWrap: "wrap" }}>
          <Typography sx={{ fontWeight: 800 }}>{selectedIds.length} selected</Typography>
          <Box sx={{ display: "flex", gap: 1, flexWrap: "wrap" }}>
            {mode === "trash" ? <Button variant="outlined" onClick={() => void runBulkAction("restore")}>Restore selected</Button> : <Button variant="outlined" color="error" onClick={() => void runBulkAction("delete")}>Delete selected</Button>}
            {mode === "jobs" ? ["Waiting", "Interview", "Rejected", "Ghosted", "Offer"].map((s) => <Button key={s} variant="outlined" onClick={() => void runBulkAction("status", s)}>{s}</Button>) : null}
          </Box>
        </Paper>
      ) : null}

      <Menu anchorEl={columnsAnchor} open={Boolean(columnsAnchor)} onClose={() => setColumnsAnchor(null)}>
        {([ ["status", "Status"], ["dateApplied", "Date applied"], ["daysSince", "Days"], ["jobUrl", "Job URL"] ] as const).map(([key, label]) => (
          <MenuItem key={key} onClick={() => onColumnsChange({ ...columns, [key]: !columns[key] })}>
            <Checkbox checked={columns[key]} />
            {label}
          </MenuItem>
        ))}
      </Menu>

      <Paper sx={{ mt: 2 }}>
        <Table size="small">
          <TableHead>
            <TableRow>
              <TableCell padding="checkbox"><Checkbox checked={selectedAllOnPage} indeterminate={selectedIds.length > 0 && !selectedAllOnPage} onChange={(e) => toggleSelectAll(e.target.checked)} /></TableCell>
              <TableCell width={1} />
              <TableCell sortDirection={sortBy === "company" ? sortDir : false}><TableSortLabel active={sortBy === "company"} direction={sortBy === "company" ? sortDir : "asc"} onClick={() => requestSort("company")}>Company</TableSortLabel></TableCell>
              <TableCell sortDirection={sortBy === "jobTitle" ? sortDir : false}><TableSortLabel active={sortBy === "jobTitle"} direction={sortBy === "jobTitle" ? sortDir : "asc"} onClick={() => requestSort("jobTitle")}>Role</TableSortLabel></TableCell>
              {columns.status ? <TableCell sortDirection={sortBy === "status" ? sortDir : false}><TableSortLabel active={sortBy === "status"} direction={sortBy === "status" ? sortDir : "asc"} onClick={() => requestSort("status")}>Status</TableSortLabel></TableCell> : null}
              {columns.dateApplied ? <TableCell sortDirection={sortBy === "dateApplied" ? sortDir : false}><TableSortLabel active={sortBy === "dateApplied"} direction={sortBy === "dateApplied" ? sortDir : "asc"} onClick={() => requestSort("dateApplied")}>Date Applied</TableSortLabel></TableCell> : null}
              {columns.daysSince ? <TableCell sortDirection={sortBy === "daysSince" ? sortDir : false}><TableSortLabel active={sortBy === "daysSince"} direction={sortBy === "daysSince" ? sortDir : "asc"} onClick={() => requestSort("daysSince")}>Days</TableSortLabel></TableCell> : null}
              {columns.jobUrl ? <TableCell>Job URL</TableCell> : null}
              <TableCell align="right">Actions</TableCell>
            </TableRow>
          </TableHead>
          <TableBody>
            {jobs.map((job) => {
              const open = expanded.includes(job.id);
              const toneName = statusTone(job.status);
              const tone = toneName === "error" ? theme.palette.error.main : toneName === "warning" ? theme.palette.warning.main : toneName === "success" ? theme.palette.success.main : toneName === "info" ? theme.palette.info.main : theme.palette.primary.main;
              return (
                <React.Fragment key={job.id}>
                  <TableRow sx={{ backgroundColor: alpha(tone, theme.palette.mode === "dark" ? 0.1 : 0.06) }}>
                    <TableCell padding="checkbox"><Checkbox checked={selectedIds.includes(job.id)} onChange={(e) => toggleSelected(job.id, e.target.checked)} /></TableCell>
                    <TableCell><IconButton size="small" onClick={() => toggleExpanded(job.id)}>{open ? <KeyboardArrowUpIcon /> : <KeyboardArrowDownIcon />}</IconButton></TableCell>
                    <TableCell>{job.company?.name ?? ""}</TableCell>
                    <TableCell>
                      <Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap" }}>
                        <span>{job.jobTitle}</span>
                        {job.needsFollowUp ? <Chip size="small" label="Follow up" title={job.followUpReason ?? undefined} sx={{ fontWeight: 800 }} /> : null}
                      </Box>
                    </TableCell>
                    {columns.status ? <TableCell><Chip label={normalizeStatus(job.status)} size="small" color={toneName as any} /></TableCell> : null}
                    {columns.dateApplied ? <TableCell>{new Date(job.dateApplied).toLocaleDateString()}</TableCell> : null}
                    {columns.daysSince ? <TableCell>{job.daysSince}</TableCell> : null}
                    {columns.jobUrl ? <TableCell>{job.jobUrl ? <a href={job.jobUrl} target="_blank" rel="noreferrer">Link</a> : ""}</TableCell> : null}
                    <TableCell align="right">
                      <Box sx={{ display: "flex", justifyContent: "flex-end", gap: 0.5 }}>
                        <Tooltip title="Edit"><IconButton size="small" onClick={() => setEditJobId(job.id)}><EditOutlinedIcon fontSize="small" /></IconButton></Tooltip>
                        <Tooltip title="Quick status"><IconButton size="small" onClick={(e) => { setStatusJobId(job.id); setStatusAnchor(e.currentTarget); }}><MoreHorizIcon fontSize="small" /></IconButton></Tooltip>
                        <Tooltip title="Open"><IconButton size="small" onClick={() => setDetailsJobId(job.id)}><LaunchIcon fontSize="small" /></IconButton></Tooltip>
                        {(mode === "trash" || (includeDeleted && job.isDeleted)) ? <Tooltip title="Restore"><IconButton size="small" onClick={() => void restore(job.id)}><RestoreFromTrashOutlinedIcon fontSize="small" /></IconButton></Tooltip> : <Tooltip title="Soft delete"><IconButton size="small" onClick={() => void softDelete(job)}><DeleteOutlineIcon fontSize="small" /></IconButton></Tooltip>}
                      </Box>
                    </TableCell>
                  </TableRow>
                  <TableRow>
                    <TableCell sx={{ py: 0 }} colSpan={columns.status && columns.dateApplied && columns.daysSince && columns.jobUrl ? 9 : 8}>
                      <Collapse in={open} timeout="auto" unmountOnExit>
                        <Box sx={{ p: 2, display: "grid", gridTemplateColumns: { xs: "1fr", md: "1fr 1fr 1fr" }, gap: 2 }}>
                          <Box><Typography variant="overline">Location</Typography><Typography>{job.location ?? "-"}</Typography></Box>
                          <Box><Typography variant="overline">Salary</Typography><Typography>{job.salary ?? "-"}</Typography></Box>
                          <Box><Typography variant="overline">Job URL</Typography><Typography>{job.jobUrl ? <a href={job.jobUrl} target="_blank" rel="noreferrer">Open listing</a> : "-"}</Typography></Box>
                          <Box sx={{ gridColumn: "1 / -1" }}><Typography variant="overline">Skills</Typography><Box sx={{ display: "flex", gap: 1, flexWrap: "wrap", mt: 0.5 }}>{parseTags(job.tags).length ? parseTags(job.tags).slice(0, 8).map((tag) => <Chip key={tag} label={tag} size="small" />) : <Typography sx={{ color: "text.secondary" }}>No tags</Typography>}</Box></Box>
                          <Box sx={{ gridColumn: "1 / -1" }}><Typography variant="overline">Overview</Typography><Typography sx={{ whiteSpace: "pre-wrap" }}>{generateOverview(job) || "No summary yet."}</Typography></Box>
                        </Box>
                      </Collapse>
                    </TableCell>
                  </TableRow>
                </React.Fragment>
              );
            })}
            {jobs.length === 0 ? <TableRow><TableCell colSpan={9}><Typography sx={{ py: 2, textAlign: "center" }}>No jobs found.</Typography></TableCell></TableRow> : null}
          </TableBody>
        </Table>
        <TablePagination component="div" count={total} page={page} onPageChange={(_, next) => setPage(next)} rowsPerPage={pageSize} onRowsPerPageChange={(e) => { onPageSizeChange(Number(e.target.value) as 15 | 20 | 25); setPage(0); }} rowsPerPageOptions={[15, 20, 25]} />
      </Paper>

      <JobDetailsDialog open={detailsJobId !== null} jobId={detailsJobId} onClose={() => setDetailsJobId(null)} />
      <EditJobDialog open={editJobId !== null} jobId={editJobId} onClose={() => setEditJobId(null)} onSaved={() => setReloadToken((t) => t + 1)} />
      <Menu anchorEl={statusAnchor} open={Boolean(statusAnchor)} onClose={() => { setStatusAnchor(null); setStatusJobId(null); }}>
        {["Waiting", "Interview", "Offer", "Rejected", "Ghosted"].map((s) => <MenuItem key={s} onClick={() => { if (statusJobId) void setStatusQuick(statusJobId, s); setStatusAnchor(null); setStatusJobId(null); }}>Set {s}</MenuItem>)}
      </Menu>
    </Box>
  );
}
