import React, { useCallback, useEffect, useState } from "react";

import { Box, Button, Checkbox, Chip, Divider, FormControlLabel, Paper, Stack, TextField, Typography } from "@mui/material";
import CheckCircleIcon from "@mui/icons-material/CheckCircle";

import { api, getApiErrorMessage } from "../api";
import { useToast } from "../toast";
import type { GmailStatus, ImapStatus, MicrosoftGraphStatus } from "../types";

// Settings > Account: connect/disconnect each linked-mailbox provider. Gmail and Microsoft use
// the same OAuth-popup + postMessage handshake (mirrored server-side in GmailController /
// MicrosoftGraphController's BuildPopupHtml); IMAP has no OAuth step, so it's a plain credential
// form submitted to POST /api/imap/connect, which verifies the connection before storing it.
export default function EmailProviderConnections() {
  const { toast } = useToast();

  const [gmailStatus, setGmailStatus] = useState<GmailStatus | null>(null);
  const [microsoftStatus, setMicrosoftStatus] = useState<MicrosoftGraphStatus | null>(null);
  const [imapStatus, setImapStatus] = useState<ImapStatus | null>(null);

  const [imapForm, setImapForm] = useState({ host: "", port: 993, useSsl: true, username: "", password: "" });
  const [imapConnecting, setImapConnecting] = useState(false);

  const loadGmailStatus = useCallback(async () => {
    try {
      const res = await api.get<GmailStatus>("/gmail/status");
      setGmailStatus(res.data);
    } catch {
      setGmailStatus({ connected: false });
    }
  }, []);

  const loadMicrosoftStatus = useCallback(async () => {
    try {
      const res = await api.get<MicrosoftGraphStatus>("/microsoft-graph/status");
      setMicrosoftStatus(res.data);
    } catch {
      setMicrosoftStatus({ connected: false });
    }
  }, []);

  const loadImapStatus = useCallback(async () => {
    try {
      const res = await api.get<ImapStatus>("/imap/status");
      setImapStatus(res.data);
    } catch {
      setImapStatus({ connected: false });
    }
  }, []);

  useEffect(() => {
    void loadGmailStatus();
    void loadMicrosoftStatus();
    void loadImapStatus();
  }, [loadGmailStatus, loadMicrosoftStatus, loadImapStatus]);

  useEffect(() => {
    const onMessage = (event: MessageEvent) => {
      const data = event.data as { source?: string; status?: string; message?: string };
      if (data?.source === "jobtracker-gmail-oauth") {
        if (data.status === "connected") {
          toast(data.message || "Gmail connected.", "success");
          void loadGmailStatus();
        } else {
          toast(data.message || "Gmail connection failed.", "error");
        }
      } else if (data?.source === "jobtracker-microsoft-oauth") {
        if (data.status === "connected") {
          toast(data.message || "Outlook connected.", "success");
          void loadMicrosoftStatus();
        } else {
          toast(data.message || "Outlook connection failed.", "error");
        }
      }
    };

    window.addEventListener("message", onMessage);
    return () => window.removeEventListener("message", onMessage);
  }, [loadGmailStatus, loadMicrosoftStatus, toast]);

  const connectViaPopup = async (connectUrlPath: string, popupName: string, providerLabel: string) => {
    try {
      const res = await api.get<{ url: string }>(connectUrlPath);
      const popup = window.open(res.data.url, popupName, "width=620,height=760,resizable=yes,scrollbars=yes");
      if (!popup) toast("Your browser blocked the connect popup. Allow popups and try again.", "error");
    } catch (error) {
      toast(getApiErrorMessage(error, `Failed to start ${providerLabel} connection.`), "error");
    }
  };

  const disconnect = async (path: string, reload: () => Promise<void>, providerLabel: string) => {
    try {
      await api.delete(path);
      await reload();
      toast(`${providerLabel} disconnected.`, "success");
    } catch (error) {
      toast(getApiErrorMessage(error, `Failed to disconnect ${providerLabel}.`), "error");
    }
  };

  const connectImap = async () => {
    if (!imapForm.host.trim() || !imapForm.username.trim() || !imapForm.password) {
      toast("Host, username, and password are required.", "error");
      return;
    }
    setImapConnecting(true);
    try {
      await api.post("/imap/connect", imapForm);
      setImapForm((prev) => ({ ...prev, password: "" }));
      await loadImapStatus();
      toast("IMAP account connected.", "success");
    } catch (error) {
      toast(getApiErrorMessage(error, "Failed to connect IMAP account."), "error");
    } finally {
      setImapConnecting(false);
    }
  };

  return (
    <Paper sx={{ p: 2 }}>
      <Typography sx={{ fontWeight: 950, mb: 0.5 }}>Linked email accounts</Typography>
      <Typography sx={{ color: "text.secondary", mb: 2 }}>
        Connect a mailbox so recruiter correspondence can be linked to jobs automatically.
      </Typography>

      <Stack spacing={2}>
        <ProviderRow
          label="Gmail"
          connected={Boolean(gmailStatus?.connected)}
          address={gmailStatus?.gmailAddress ?? null}
          onConnect={() => void connectViaPopup("/gmail/connect-url", "jobtracker-gmail-connect", "Gmail")}
          onDisconnect={() => void disconnect("/gmail/connection", loadGmailStatus, "Gmail")}
        />

        <Divider />

        <ProviderRow
          label="Outlook / Microsoft 365"
          connected={Boolean(microsoftStatus?.connected)}
          address={microsoftStatus?.mailAddress ?? null}
          onConnect={() => void connectViaPopup("/microsoft-graph/connect-url", "jobtracker-microsoft-connect", "Outlook")}
          onDisconnect={() => void disconnect("/microsoft-graph/connection", loadMicrosoftStatus, "Outlook")}
        />

        <Divider />

        <Box>
          <ProviderRow
            label="Other (IMAP)"
            connected={Boolean(imapStatus?.connected)}
            address={imapStatus?.username ?? null}
            onDisconnect={() => void disconnect("/imap/connection", loadImapStatus, "IMAP")}
          />
          {!imapStatus?.connected && (
            <Box sx={{ mt: 1.5, display: "grid", gap: 1.25, gridTemplateColumns: { xs: "1fr", sm: "2fr 1fr" }, maxWidth: 520 }}>
              <TextField
                size="small"
                label="IMAP host"
                placeholder="imap.example.com"
                value={imapForm.host}
                onChange={(e) => setImapForm((prev) => ({ ...prev, host: e.target.value }))}
              />
              <TextField
                size="small"
                label="Port"
                type="number"
                value={imapForm.port}
                onChange={(e) => setImapForm((prev) => ({ ...prev, port: Number(e.target.value) || 993 }))}
              />
              <TextField
                size="small"
                label="Username"
                value={imapForm.username}
                onChange={(e) => setImapForm((prev) => ({ ...prev, username: e.target.value }))}
                sx={{ gridColumn: "1 / -1" }}
              />
              <TextField
                size="small"
                label="Password"
                type="password"
                value={imapForm.password}
                onChange={(e) => setImapForm((prev) => ({ ...prev, password: e.target.value }))}
                sx={{ gridColumn: "1 / -1" }}
              />
              <FormControlLabel
                sx={{ gridColumn: "1 / -1" }}
                control={<Checkbox checked={imapForm.useSsl} onChange={(e) => setImapForm((prev) => ({ ...prev, useSsl: e.target.checked }))} />}
                label="Use SSL/TLS"
              />
              <Button
                variant="contained"
                onClick={connectImap}
                disabled={imapConnecting}
                sx={{ gridColumn: "1 / -1", justifySelf: "start" }}
              >
                {imapConnecting ? "Connecting…" : "Connect IMAP account"}
              </Button>
            </Box>
          )}
        </Box>
      </Stack>
    </Paper>
  );
}

function ProviderRow({
  label,
  connected,
  address,
  onConnect,
  onDisconnect,
}: {
  label: string;
  connected: boolean;
  address: string | null;
  onConnect?: () => void;
  onDisconnect: () => void;
}) {
  return (
    <Stack direction="row" alignItems="center" justifyContent="space-between" flexWrap="wrap" gap={1}>
      <Box>
        <Typography sx={{ fontWeight: 700 }}>{label}</Typography>
        {connected ? (
          <Chip
            size="small"
            icon={<CheckCircleIcon fontSize="small" />}
            color="success"
            variant="outlined"
            label={address || "Connected"}
            sx={{ mt: 0.5 }}
          />
        ) : (
          <Typography variant="caption" sx={{ color: "text.secondary" }}>Not connected</Typography>
        )}
      </Box>
      {connected ? (
        <Button size="small" variant="outlined" color="error" onClick={onDisconnect}>Disconnect</Button>
      ) : (
        onConnect && <Button size="small" variant="outlined" onClick={onConnect}>Connect</Button>
      )}
    </Stack>
  );
}
