import * as React from "react";
import {
  Box,
  Container,
  Paper,
  Typography,
  Button,
  ToggleButtonGroup,
  ToggleButton,
  Chip,
  IconButton,
  CircularProgress,
  Alert,
  Snackbar,
  Dialog,
  DialogTitle,
  DialogContent,
  DialogContentText,
  DialogActions,
  Tooltip,
  TextField,
  Select,
  MenuItem,
  InputLabel,
  FormControl,
  OutlinedInput,
  Autocomplete,
  Table,
  TableBody,
  TableCell,
  TableContainer,
  TableHead,
  TableRow,
} from "@mui/material";
import DeleteIcon from "@mui/icons-material/Delete";
import CloudUploadIcon from "@mui/icons-material/CloudUpload";
import RefreshIcon from "@mui/icons-material/Refresh";
import ContentCopyIcon from "@mui/icons-material/ContentCopy";
import ReplayIcon from "@mui/icons-material/Replay";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";
import ErrorIcon from "@mui/icons-material/Error";
import ScheduleIcon from "@mui/icons-material/Schedule";
import HourglassEmptyIcon from "@mui/icons-material/HourglassEmpty";
import WarningAmberIcon from "@mui/icons-material/WarningAmber";
import { useUploadFile } from "./features/fetch-requests";
import type {
  FetchRequest,
  FetchRequestStatus,
  FileSource,
  EmailSource,
} from "./features/fetch-requests";
import { RETRY_MAX, formatApiError } from "./features/fetch-requests";
import { useNavigate } from "react-router-dom";
import { useResource, FormFieldRenderer, applyDisplayFormat } from "../react-openapi";
import type { FieldConfig } from "../react-openapi";
import { useMutation, useQuery } from "@tanstack/react-query";

const statusColors: Record<FetchRequestStatus, "default" | "primary" | "warning" | "info" | "success" | "error"> = {
  pending: "default",
  processing: "info",
  paused: "warning",
  raw_expenses_done: "primary",
  enriched_done: "warning",
  completed: "success",
  failed: "error",
};

const statusIcons: Record<FetchRequestStatus, React.ReactNode> = {
  pending: <ScheduleIcon sx={{ fontSize: 16 }} />,
  processing: <CircularProgress size={14} sx={{ mr: 0.5 }} />,
  paused: <WarningAmberIcon sx={{ fontSize: 16, color: "warning.main" }} />,
  raw_expenses_done: <HourglassEmptyIcon sx={{ fontSize: 16 }} />,
  enriched_done: <HourglassEmptyIcon sx={{ fontSize: 16 }} />,
  completed: <CheckCircleIcon sx={{ fontSize: 16, color: "success.main" }} />,
  failed: <ErrorIcon sx={{ fontSize: 16, color: "error.main" }} />,
};

const STATUS_OPTIONS: FetchRequestStatus[] = [
  "pending",
  "processing",
  "paused",
  "raw_expenses_done",
  "enriched_done",
  "completed",
  "failed",
];

function shortId(fp: string) {
  return fp.length > 8 ? fp.slice(0, 8) + "\u2026" : fp;
}

export default function FetchRequests() {
  const navigate = useNavigate();

  const [sourceType, setSourceType] = React.useState<"file" | "email">("file");
  const [accountName, setAccountName] = React.useState("");
  const [payorUsername, setPayorUsername] = React.useState("aetos");
  const [format, setFormat] = React.useState("");
  const [file, setFile] = React.useState<File | null>(null);
  const [uploadedPath, setUploadedPath] = React.useState<string | null>(null);
  const [fromEmail, setFromEmail] = React.useState("");
  const [subject, setSubject] = React.useState("");
  const [rawTerms, setRawTerms] = React.useState("");
  const [startDate, setStartDate] = React.useState("");
  const [endDate, setEndDate] = React.useState("");
  const [snackbar, setSnackbar] = React.useState<{ message: string; severity: "success" | "error" } | null>(null);
  const [deleteTarget, setDeleteTarget] = React.useState<FetchRequest | null>(null);

  const [statusFilter, setStatusFilter] = React.useState<string[]>([]);
  const [accountFilter, setAccountFilter] = React.useState("");
  const [sourceFilter, setSourceFilter] = React.useState<"all" | "file" | "email">("all");

  const { list, create, update, remove, resource: fetchRes } = useResource("fetch-requests");

  const { data: listData, isLoading, isFetching, refetch } = useQuery({
    queryKey: ["fetch-requests", "list", { statusFilter, accountFilter, sourceFilter }],
    queryFn: () => list({
      ...(statusFilter.length > 0 ? { status: statusFilter.join(",") } : {}),
      ...(accountFilter ? { account_name: accountFilter } : {}),
      ...(sourceFilter !== "all" ? { source_type: sourceFilter } : {}),
    }),
  });

  const { list: listAccounts } = useResource("accounts");
  const { data: accountsData } = useQuery({
    queryKey: ["accounts", "list"],
    queryFn: () => listAccounts(),
  });
  const accountOptions: string[] = React.useMemo(() => {
    return (accountsData?.items ?? []).map((a: any) => a.name).filter(Boolean);
  }, [accountsData]);

  const fields = fetchRes?.orderedFields ?? [];
  const formatField: FieldConfig | undefined = fields.find(f => f.name === "format");
  const startDateField: FieldConfig | undefined = fields.find(f => f.name === "start_date");
  const endDateField: FieldConfig | undefined = fields.find(f => f.name === "end_date");
  const payorUsernameField: FieldConfig | undefined = fields.find(f => f.name === "payor_username");

  const createMutation = useMutation({ mutationFn: (data: any) => create(data) });
  const updateMutation = useMutation({
    mutationFn: ({ id, data }: { id: string; data: any }) => update(id, data),
  });
  const deleteMutation = useMutation({ mutationFn: (id: string) => remove(id) });
  const uploadMutation = useUploadFile();

  const requests = listData?.items ?? [];

  const handleUpload = async () => {
    if (!file) return;
    const result = await uploadMutation.mutateAsync(file);
    if (result?.saved_as) {
      setUploadedPath(result.saved_as);
      if (!format) setFormat(file.name.split(".").pop() || "");
      setSnackbar({ message: `File uploaded: ${result.saved_as}`, severity: "success" });
    }
  };

  const handleCreate = async () => {
    if (!accountName) return;

    let source: FileSource | EmailSource;

    if (sourceType === "file") {
      if (!uploadedPath || !format) return;
      source = { path: uploadedPath, format } as FileSource;
    } else {
      if (!format) return;
      const emailSource: EmailSource = { format };
      if (fromEmail) emailSource.from_email = fromEmail;
      if (subject) emailSource.subject = subject;
      if (rawTerms.trim()) emailSource.raw_terms = rawTerms.split(",").map((s) => s.trim()).filter(Boolean);
      source = emailSource;
    }

    try {
      const result = await createMutation.mutateAsync({
        source,
        account_name: accountName,
        payor_username: payorUsername,
        ...(startDate ? { start_date: new Date(startDate).toISOString() } : {}),
        ...(endDate ? { end_date: new Date(endDate).toISOString() } : {}),
      });
      setSnackbar({ message: "Fetch request created", severity: "success" });
      resetForm();
      navigate(`/fetch-requests/${result.id}`);
    } catch (err: any) {
      if (err?.response?.status === 409) {
        setSnackbar({ message: "Duplicate — same fingerprint already exists", severity: "error" });
      } else {
        setSnackbar({ message: formatApiError(err) || "Failed to create fetch request", severity: "error" });
      }
    }
  };

  const resetForm = () => {
    setAccountName("");
    setFormat("");
    setFile(null);
    setUploadedPath(null);
    setFromEmail("");
    setSubject("");
    setRawTerms("");
    setStartDate("");
    setEndDate("");
  };

  const handleRetry = async (req: FetchRequest) => {
    try {
      await updateMutation.mutateAsync({ id: req.id, data: { status: "pending" } });
      setSnackbar({ message: "Retrying fetch request", severity: "success" });
    } catch {
      setSnackbar({ message: "Failed to retry", severity: "error" });
    }
  };

  const handleDelete = async () => {
    if (!deleteTarget) return;
    try {
      await deleteMutation.mutateAsync(deleteTarget.id);
      setSnackbar({ message: "Fetch request deleted", severity: "success" });
    } catch {
      setSnackbar({ message: "Failed to delete", severity: "error" });
    }
    setDeleteTarget(null);
  };

  return (
    <Container sx={{ mt: 4, mb: 4 }}>
      <Typography variant="h5" fontWeight="bold" gutterBottom>
        Fetch Request Pipeline
      </Typography>

      {/* Create Form */}
      <Paper sx={{ p: 3, mb: 4, borderRadius: 4 }} variant="outlined">
        <Typography variant="subtitle1" fontWeight={600} gutterBottom>
          New Fetch Request
        </Typography>

        <ToggleButtonGroup
          value={sourceType}
          exclusive
          onChange={(_, val) => val && setSourceType(val)}
          sx={{ mb: 3 }}
          size="small"
        >
          <ToggleButton value="file">File Upload</ToggleButton>
          <ToggleButton value="email">Email Fetch</ToggleButton>
        </ToggleButtonGroup>

        <Box sx={{ display: "flex", flexDirection: "column", gap: 2 }}>
          {sourceType === "file" ? (
            <>
              <Box sx={{ display: "flex", gap: 2, alignItems: "flex-end" }}>
                <Button variant="outlined" component="label" startIcon={<CloudUploadIcon />}>
                  Choose File
                  <input type="file" hidden onChange={(e) => setFile(e.target.files?.[0] ?? null)} />
                </Button>
                <Typography variant="body2" sx={{ flex: 1, color: "text.secondary" }}>
                  {file ? file.name : "No file selected"}
                </Typography>
                <Button
                  variant="contained"
                  onClick={handleUpload}
                  disabled={!file || uploadMutation.isPending}
                >
                  {uploadMutation.isPending ? "Uploading..." : "Upload"}
                </Button>
              </Box>
              {uploadedPath && (
                <Alert severity="success" sx={{ py: 0 }}>
                  Uploaded as: {uploadedPath}
                </Alert>
              )}
              {formatField && (
                <FormFieldRenderer field={formatField} value={format} onChange={setFormat} />
              )}
            </>
          ) : (
            <>
              {formatField && (
                <FormFieldRenderer field={formatField} value={format} onChange={setFormat} />
              )}
              <TextField label="From Email" value={fromEmail} onChange={(e) => setFromEmail(e.target.value)} size="small" />
              <TextField label="Subject" value={subject} onChange={(e) => setSubject(e.target.value)} size="small" />
              <TextField label="Raw Terms" value={rawTerms} onChange={(e) => setRawTerms(e.target.value)} size="small" helperText="Comma-separated search terms" />
            </>
          )}

          <Autocomplete
            options={accountOptions}
            value={accountName || null}
            onChange={(_, val) => setAccountName(val ?? "")}
            renderInput={(params) => (
              <TextField {...params} label="Account Name" size="small" required />
            )}
          />

          {payorUsernameField && (
            <FormFieldRenderer field={payorUsernameField} value={payorUsername} onChange={setPayorUsername} />
          )}

          <Box sx={{ display: "flex", gap: 2 }}>
            {startDateField && (
              <Box sx={{ flex: 1 }}>
                <FormFieldRenderer field={startDateField} value={startDate} onChange={setStartDate} />
              </Box>
            )}
            {endDateField && (
              <Box sx={{ flex: 1 }}>
                <FormFieldRenderer field={endDateField} value={endDate} onChange={setEndDate} />
              </Box>
            )}
          </Box>

          <Button
            variant="contained"
            onClick={handleCreate}
            disabled={createMutation.isPending || !accountName || (sourceType === "file" && (!uploadedPath || !format)) || (sourceType === "email" && !format)}
          >
            {createMutation.isPending ? "Creating..." : "Create Fetch Request"}
          </Button>
        </Box>
      </Paper>

      {/* Filters */}
      <Paper sx={{ borderRadius: 4, mb: 2, p: 2 }} variant="outlined">
        <Box sx={{ display: "flex", alignItems: "center", gap: 2, flexWrap: "wrap" }}>
          <FormControl size="small" sx={{ minWidth: 200 }}>
            <InputLabel>Status</InputLabel>
            <Select
              multiple
              value={statusFilter}
              onChange={(e) => setStatusFilter(e.target.value as string[])}
              input={<OutlinedInput label="Status" />}
              renderValue={(selected) => (selected as string[]).join(", ")}
            >
              {STATUS_OPTIONS.map((s) => (
                <MenuItem key={s} value={s}>{s.replace(/_/g, " ")}</MenuItem>
              ))}
            </Select>
          </FormControl>
          <Autocomplete
            options={accountOptions}
            value={accountFilter || null}
            onChange={(_, val) => setAccountFilter(val ?? "")}
            renderInput={(params) => (
              <TextField {...params} label="Account" size="small" sx={{ minWidth: 160 }} />
            )}
            sx={{ minWidth: 160 }}
          />
          <ToggleButtonGroup
            value={sourceFilter}
            exclusive
            onChange={(_, val) => val && setSourceFilter(val)}
            size="small"
          >
            <ToggleButton value="all">All</ToggleButton>
            <ToggleButton value="file">File</ToggleButton>
            <ToggleButton value="email">Email</ToggleButton>
          </ToggleButtonGroup>
          <Box sx={{ flex: 1 }} />
          <IconButton onClick={() => refetch()} disabled={isFetching}>
            <RefreshIcon />
          </IconButton>
        </Box>
      </Paper>

      {/* List Table */}
      {isLoading ? (
        <Box sx={{ display: "flex", justifyContent: "center", p: 4 }}>
          <CircularProgress />
        </Box>
      ) : requests.length === 0 ? (
        <Box sx={{ p: 4, textAlign: "center", color: "text.secondary" }}>
          No fetch requests yet
        </Box>
      ) : (
        <TableContainer component={Paper} variant="outlined" sx={{ borderRadius: 4 }}>
          <Table size="small">
            <TableHead>
              <TableRow>
                <TableCell>ID</TableCell>
                <TableCell>Account</TableCell>
                <TableCell>Source</TableCell>
                <TableCell>Date Range</TableCell>
                <TableCell>Status</TableCell>
                <TableCell>Retries</TableCell>
                <TableCell>Created</TableCell>
                <TableCell align="right">Actions</TableCell>
              </TableRow>
            </TableHead>
            <TableBody>
              {[...requests]
                .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
                .map((req: FetchRequest) => (
                  <TableRow
                    key={req.id}
                    hover
                    sx={{ cursor: "pointer" }}
                    onClick={() => navigate(`/fetch-requests/${req.id}`)}
                  >
                    <TableCell>
                      <Box sx={{ display: "flex", alignItems: "center", gap: 0.5 }}>
                        <Typography variant="body2" sx={{ fontFamily: "monospace", fontSize: "0.8rem" }}>
                          {shortId(req.fingerprint)}
                        </Typography>
                        <IconButton
                          size="small"
                          onClick={(e) => {
                            e.stopPropagation();
                            navigator.clipboard.writeText(req.fingerprint);
                            setSnackbar({ message: "Copied!", severity: "success" });
                          }}
                          sx={{ opacity: 0.5, '&:hover': { opacity: 1 } }}
                        >
                          <ContentCopyIcon sx={{ fontSize: 14 }} />
                        </IconButton>
                      </Box>
                    </TableCell>
                    <TableCell>{req.account_name}</TableCell>
                    <TableCell>
                      <Chip
                        label={"path" in req.source ? "File" : "Email"}
                        size="small"
                        variant="outlined"
                        color={"path" in req.source ? "primary" : "secondary"}
                      />
                    </TableCell>
                    <TableCell>
                      <Typography variant="body2" sx={{ fontSize: "0.8rem", whiteSpace: "nowrap" }}>
                        {(req as any).start_date ? new Date((req as any).start_date).toLocaleDateString() : "?"} → {(req as any).end_date ? new Date((req as any).end_date).toLocaleDateString() : "?"}
                      </Typography>
                    </TableCell>
                    <TableCell>
                      <Tooltip title={req.error_message || req.status.replace(/_/g, " ")}>
                        <Chip
                          icon={statusIcons[req.status] as any}
                          label={req.status.replace(/_/g, " ")}
                          color={statusColors[req.status]}
                          size="small"
                        />
                      </Tooltip>
                    </TableCell>
                    <TableCell>
                      <Typography variant="body2" sx={{ fontSize: "0.8rem" }}>
                        {(req.retry_count ?? 0) > 0 ? `${req.retry_count}/${RETRY_MAX}` : "—"}
                      </Typography>
                    </TableCell>
                    <TableCell>
                      <Typography variant="body2" sx={{ fontSize: "0.8rem", whiteSpace: "nowrap" }}>
                        {new Date(req.created_at).toLocaleString()}
                      </Typography>
                    </TableCell>
                    <TableCell align="right">
                      <Box sx={{ display: "flex", gap: 0.5, justifyContent: "flex-end" }}>
                        {req.status === "paused" && (
                          <Tooltip title="Resolve ambiguities">
                            <IconButton size="small" onClick={(e) => { e.stopPropagation(); navigate(`/fetch-requests/${req.id}`); }}>
                              <WarningAmberIcon fontSize="small" color="warning" />
                            </IconButton>
                          </Tooltip>
                        )}
                        {req.status === "failed" && (req.retry_count ?? 0) < RETRY_MAX && (
                          <Tooltip title="Retry">
                            <IconButton size="small" onClick={(e) => { e.stopPropagation(); handleRetry(req); }}>
                              <ReplayIcon fontSize="small" />
                            </IconButton>
                          </Tooltip>
                        )}
                        <Tooltip title="Delete">
                          <IconButton size="small" onClick={(e) => { e.stopPropagation(); setDeleteTarget(req); }}>
                            <DeleteIcon fontSize="small" />
                          </IconButton>
                        </Tooltip>
                      </Box>
                    </TableCell>
                  </TableRow>
                ))}
            </TableBody>
          </Table>
        </TableContainer>
      )}

      <Snackbar
        open={!!snackbar}
        autoHideDuration={4000}
        onClose={() => setSnackbar(null)}
        anchorOrigin={{ vertical: "bottom", horizontal: "center" }}
      >
        {snackbar ? <Alert severity={snackbar.severity} onClose={() => setSnackbar(null)}>{snackbar.message}</Alert> : undefined}
      </Snackbar>

      <Dialog open={!!deleteTarget} onClose={() => setDeleteTarget(null)}>
        <DialogTitle>Delete Fetch Request?</DialogTitle>
        <DialogContent>
          <DialogContentText>
            This will permanently delete the fetch request and all associated data.
          </DialogContentText>
        </DialogContent>
        <DialogActions>
          <Button onClick={() => setDeleteTarget(null)}>Cancel</Button>
          <Button onClick={handleDelete} color="error" disabled={deleteMutation.isPending}>
            {deleteMutation.isPending ? "Deleting..." : "Delete"}
          </Button>
        </DialogActions>
      </Dialog>
    </Container>
  );
}
