import { useEffect, useRef, useState, useCallback } from 'react';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { useTranslation } from 'react-i18next';
import {
  Loader2,
  RefreshCw,
  RotateCw,
  CheckCircle2,
  XCircle,
} from 'lucide-react';
import QRCode from 'qrcode';
import { getActiveWorkspaceUuid } from '@/app/infra/http/workspaceContext';

export type QrLoginPlatform =
  | 'feishu'
  | 'weixin'
  | 'dingtalk'
  | 'wecombot'
  | 'qqofficial';

interface PlatformConfig {
  titleKey: string;
  connectingKey: string;
  scanQRCodeKey: string;
  waitingKey: string;
  successKey: string;
  failedKey: string;
  retryKey: string;
  apiBase: string;
  extractSuccess: (data: Record<string, string>) => Record<string, string>;
  successNoteKey?: string;
  boundByKey?: string;
}

const PLATFORM_CONFIGS: Record<QrLoginPlatform, PlatformConfig> = {
  feishu: {
    titleKey: 'feishu.createApp',
    connectingKey: 'feishu.connecting',
    scanQRCodeKey: 'feishu.scanQRCode',
    waitingKey: 'feishu.waitingForScan',
    successKey: 'feishu.createSuccess',
    failedKey: 'feishu.createFailed',
    retryKey: 'feishu.retry',
    apiBase: '/api/v1/platform/adapters/lark/create-app',
    extractSuccess: (data) => ({
      app_id: data.app_id,
      app_secret: data.app_secret,
      ...(data.app_name ? { app_name: data.app_name } : {}),
    }),
  },
  weixin: {
    titleKey: 'weixin.scanLogin',
    connectingKey: 'weixin.connecting',
    scanQRCodeKey: 'weixin.scanQRCode',
    waitingKey: 'weixin.waitingForScan',
    successKey: 'weixin.loginSuccess',
    failedKey: 'weixin.loginFailed',
    retryKey: 'weixin.retry',
    apiBase: '/api/v1/platform/adapters/weixin/login',
    extractSuccess: (data) => ({
      token: data.token,
      base_url: data.base_url,
      ...(data.account_id ? { account_id: data.account_id } : {}),
    }),
  },
  dingtalk: {
    titleKey: 'dingtalk.createApp',
    connectingKey: 'dingtalk.connecting',
    scanQRCodeKey: 'dingtalk.scanQRCode',
    waitingKey: 'dingtalk.waitingForScan',
    successKey: 'dingtalk.createSuccess',
    failedKey: 'dingtalk.createFailed',
    retryKey: 'dingtalk.retry',
    apiBase: '/api/v1/platform/adapters/dingtalk/create-app',
    extractSuccess: (data) => ({
      client_id: data.client_id,
      client_secret: data.client_secret,
    }),
    successNoteKey: 'dingtalk.robotCodeNote',
  },
  wecombot: {
    titleKey: 'wecombot.createBot',
    connectingKey: 'wecombot.connecting',
    scanQRCodeKey: 'wecombot.scanQRCode',
    waitingKey: 'wecombot.waitingForScan',
    successKey: 'wecombot.createSuccess',
    failedKey: 'wecombot.createFailed',
    retryKey: 'wecombot.retry',
    apiBase: '/api/v1/platform/adapters/wecombot/create-bot',
    extractSuccess: (data) => ({
      BotId: data.botid,
      Secret: data.secret,
    }),
    successNoteKey: 'wecombot.robotNameNote',
  },
  qqofficial: {
    titleKey: 'qqofficial.createBinding',
    connectingKey: 'qqofficial.connecting',
    scanQRCodeKey: 'qqofficial.scanQRCode',
    waitingKey: 'qqofficial.waitingForScan',
    successKey: 'qqofficial.bindSuccess',
    failedKey: 'qqofficial.bindFailed',
    retryKey: 'qqofficial.retry',
    apiBase: '/api/v1/platform/adapters/qqofficial/bind',
    extractSuccess: (data) => ({
      appid: data.appid,
      secret: data.secret,
    }),
    successNoteKey: 'qqofficial.tokenNote',
    boundByKey: 'qqofficial.boundBy',
  },
};

interface QrCodeLoginDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  platform: QrLoginPlatform;
  onSuccess: (credentials: Record<string, string>) => void;
}

type DialogState = 'connecting' | 'waiting' | 'expired' | 'success' | 'error';

const POLL_INTERVAL_MS = 3000;

export default function QrCodeLoginDialog({
  open,
  onOpenChange,
  platform,
  onSuccess,
}: QrCodeLoginDialogProps) {
  const { t } = useTranslation();
  const platformConfig = PLATFORM_CONFIGS[platform];

  const [state, setState] = useState<DialogState>('connecting');
  const [qrDataUrl, setQrDataUrl] = useState('');
  const [expireIn, setExpireIn] = useState(0);
  const [errorMessage, setErrorMessage] = useState('');
  const [successMeta, setSuccessMeta] = useState('');
  const pollTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const countdownRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const checkExpiredRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const abortRef = useRef<AbortController | null>(null);
  const sessionIdRef = useRef<string | null>(null);
  const sessionWorkspaceUuidRef = useRef<string | null>(null);
  const sessionApiBaseRef = useRef('');
  const baseUrlRef = useRef('');
  const cleanedRef = useRef(false);

  const onSuccessRef = useRef(onSuccess);
  onSuccessRef.current = onSuccess;
  const onOpenChangeRef = useRef(onOpenChange);
  onOpenChangeRef.current = onOpenChange;
  const tRef = useRef(t);
  tRef.current = t;
  const platformConfigRef = useRef(platformConfig);
  platformConfigRef.current = platformConfig;

  const cleanup = useCallback(() => {
    if (cleanedRef.current) return;
    cleanedRef.current = true;

    if (pollTimerRef.current) {
      clearInterval(pollTimerRef.current);
      pollTimerRef.current = null;
    }
    if (countdownRef.current) {
      clearInterval(countdownRef.current);
      countdownRef.current = null;
    }
    if (checkExpiredRef.current) {
      clearInterval(checkExpiredRef.current);
      checkExpiredRef.current = null;
    }
    if (abortRef.current) {
      abortRef.current.abort();
      abortRef.current = null;
    }
    if (sessionIdRef.current) {
      const token = localStorage.getItem('token');
      const workspaceUuid = sessionWorkspaceUuidRef.current;
      fetch(
        `${baseUrlRef.current}${sessionApiBaseRef.current}/${sessionIdRef.current}`,
        {
          method: 'DELETE',
          headers: {
            Authorization: `Bearer ${token}`,
            ...(workspaceUuid ? { 'X-Workspace-Id': workspaceUuid } : {}),
          },
          keepalive: true,
        },
      ).catch(() => {});
      sessionIdRef.current = null;
    }
    sessionWorkspaceUuidRef.current = null;
    sessionApiBaseRef.current = '';
    baseUrlRef.current = '';
  }, []);

  const startLogin = useCallback(async () => {
    cleanup();
    cleanedRef.current = false;
    setState('connecting');
    setQrDataUrl('');
    setExpireIn(0);
    setErrorMessage('');
    setSuccessMeta('');

    const token = localStorage.getItem('token');
    const workspaceUuid = getActiveWorkspaceUuid();
    const baseUrl = import.meta.env.VITE_API_BASE_URL || window.location.origin;
    baseUrlRef.current = baseUrl;
    const cfg = platformConfigRef.current;

    try {
      const controller = new AbortController();
      abortRef.current = controller;

      const res = await fetch(`${baseUrl}${cfg.apiBase}`, {
        method: 'POST',
        headers: {
          Authorization: `Bearer ${token}`,
          ...(workspaceUuid ? { 'X-Workspace-Id': workspaceUuid } : {}),
        },
        signal: controller.signal,
      });

      if (!res.ok) throw new Error(`HTTP ${res.status}`);

      const json = await res.json();
      if (json.code !== 0) throw new Error(json.msg || 'Request failed');

      const { session_id, qr_data_url, qr_url, expire_at } = json.data;
      sessionIdRef.current = session_id;
      sessionWorkspaceUuidRef.current = workspaceUuid;
      sessionApiBaseRef.current = cfg.apiBase;

      if (qr_data_url) {
        setQrDataUrl(qr_data_url);
      } else if (qr_url) {
        const dataUrl = await QRCode.toDataURL(qr_url, {
          width: 224,
          margin: 2,
        });
        setQrDataUrl(dataUrl);
      }
      setState('waiting');

      const remaining = Math.max(0, Math.floor(expire_at - Date.now() / 1000));
      setExpireIn(remaining);

      countdownRef.current = setInterval(() => {
        setExpireIn((prev) => {
          if (prev <= 1) {
            if (countdownRef.current) {
              clearInterval(countdownRef.current);
              countdownRef.current = null;
            }
            return 0;
          }
          return prev - 1;
        });
      }, 1000);

      // When countdown hits 0, stop polling and show expired state
      checkExpiredRef.current = setInterval(() => {
        setExpireIn((current) => {
          if (current <= 0) {
            if (checkExpiredRef.current) {
              clearInterval(checkExpiredRef.current);
              checkExpiredRef.current = null;
            }
            if (pollTimerRef.current) {
              clearInterval(pollTimerRef.current);
              pollTimerRef.current = null;
            }
            if (sessionIdRef.current) {
              fetch(
                `${baseUrlRef.current}${cfg.apiBase}/${sessionIdRef.current}`,
                {
                  method: 'DELETE',
                  headers: {
                    Authorization: `Bearer ${token}`,
                    ...(workspaceUuid
                      ? { 'X-Workspace-Id': workspaceUuid }
                      : {}),
                  },
                  keepalive: true,
                },
              ).catch(() => {});
              sessionIdRef.current = null;
              sessionWorkspaceUuidRef.current = null;
              sessionApiBaseRef.current = '';
              baseUrlRef.current = '';
            }
            setState('expired');
          }
          return current;
        });
      }, 500);

      pollTimerRef.current = setInterval(async () => {
        try {
          const pollRes = await fetch(
            `${baseUrl}${cfg.apiBase}/status/${session_id}`,
            {
              headers: {
                Authorization: `Bearer ${token}`,
                ...(workspaceUuid ? { 'X-Workspace-Id': workspaceUuid } : {}),
              },
            },
          );
          if (!pollRes.ok) return;

          const pollJson = await pollRes.json();
          if (pollJson.code !== 0) return;

          const { status, error, ...rest } = pollJson.data;

          if (status === 'success') {
            sessionIdRef.current = null;
            cleanup();
            setState('success');
            // Platform may return extra audit metadata (e.g. QQ Official returns
            // the scanner's user_openid) — surface it briefly before the dialog closes.
            if (rest.user_openid && cfg.boundByKey) {
              setSuccessMeta(
                tRef.current(cfg.boundByKey, { openid: rest.user_openid }),
              );
            }
            setTimeout(() => {
              onSuccessRef.current(cfg.extractSuccess(rest));
              onOpenChangeRef.current(false);
            }, 1500);
          } else if (status === 'error') {
            sessionIdRef.current = null;
            cleanup();
            setState('error');
            setErrorMessage(error || tRef.current(cfg.failedKey));
          } else if (status === 'expired') {
            sessionIdRef.current = null;
            cleanup();
            setExpireIn(0);
            setState('expired');
          }
        } catch {
          // ignore poll errors
        }
      }, POLL_INTERVAL_MS);
    } catch (err: unknown) {
      if (err instanceof Error && err.name === 'AbortError') return;
      setState('error');
      setErrorMessage(
        err instanceof Error ? err.message : tRef.current(cfg.failedKey),
      );
    }
  }, [cleanup]);

  useEffect(() => {
    if (open) {
      startLogin();
    }
    return () => {
      cleanup();
    };
  }, [open, startLogin, cleanup]);

  const handleOpenChange = (newOpen: boolean) => {
    if (!newOpen) {
      cleanup();
    }
    onOpenChange(newOpen);
  };

  const formatTime = (seconds: number) => {
    const m = Math.floor(seconds / 60);
    const s = seconds % 60;
    if (m > 0) {
      return `${m}m${s.toString().padStart(2, '0')}s`;
    }
    return `${s}s`;
  };

  return (
    <Dialog open={open} onOpenChange={handleOpenChange}>
      <DialogContent className="sm:max-w-md">
        <DialogHeader>
          <DialogTitle>{t(platformConfig.titleKey)}</DialogTitle>
        </DialogHeader>

        <div className="flex flex-col items-center justify-center py-4 space-y-4">
          {/* Connecting */}
          {state === 'connecting' && (
            <div className="flex flex-col items-center space-y-3 py-8">
              <Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
              <p className="text-sm text-muted-foreground">
                {t(platformConfig.connectingKey)}
              </p>
            </div>
          )}

          {/* QR code area */}
          {state === 'waiting' && qrDataUrl && (
            <div className="flex flex-col items-center space-y-3">
              <p className="text-sm text-muted-foreground text-center">
                {t(platformConfig.scanQRCodeKey)}
              </p>
              <div className="border rounded-lg p-2 bg-white">
                <img src={qrDataUrl} alt="QR Code" className="w-56 h-56" />
              </div>
              {expireIn > 0 && (
                <p className="text-xs text-muted-foreground">
                  {t(platformConfig.waitingKey)} ({formatTime(expireIn)})
                </p>
              )}
            </div>
          )}

          {/* QR code expired — click overlay to refresh */}
          {state === 'expired' && qrDataUrl && (
            <div className="flex flex-col items-center space-y-3">
              <p className="text-sm text-muted-foreground text-center">
                {t(platformConfig.scanQRCodeKey)}
              </p>
              <button
                type="button"
                className="relative border rounded-lg p-2 bg-white cursor-pointer group"
                onClick={() => startLogin()}
              >
                <img
                  src={qrDataUrl}
                  alt="QR Code"
                  className="w-56 h-56 opacity-40"
                />
                <div className="absolute inset-0 flex items-center justify-center bg-white/60 rounded-lg group-hover:bg-white/70 transition-colors">
                  <div className="flex items-center justify-center w-16 h-16 rounded-full bg-black/5 group-hover:bg-black/10 transition-colors">
                    <RotateCw className="h-8 w-8 text-muted-foreground" />
                  </div>
                </div>
              </button>
            </div>
          )}

          {/* Success */}
          {state === 'success' && (
            <div className="flex flex-col items-center space-y-3 py-8">
              <CheckCircle2 className="h-12 w-12 text-green-500" />
              <p className="text-sm text-green-600 font-medium">
                {t(platformConfig.successKey)}
              </p>
              {successMeta && (
                <p className="text-xs text-muted-foreground text-center max-w-xs break-all">
                  {successMeta}
                </p>
              )}
              {platformConfig.successNoteKey && (
                <p className="text-xs text-muted-foreground text-center max-w-xs">
                  {t(platformConfig.successNoteKey)}
                </p>
              )}
            </div>
          )}

          {/* Error */}
          {state === 'error' && (
            <div className="flex flex-col items-center space-y-3 py-8">
              <XCircle className="h-12 w-12 text-red-500" />
              <p className="text-sm text-red-600 text-center">
                {errorMessage || t(platformConfig.failedKey)}
              </p>
            </div>
          )}
        </div>

        {state === 'error' && (
          <div className="flex justify-end gap-2">
            <Button variant="outline" onClick={() => handleOpenChange(false)}>
              {t('common.cancel')}
            </Button>
            <Button onClick={() => startLogin()}>
              <RefreshCw className="h-4 w-4 mr-1.5" />
              {t(platformConfig.retryKey)}
            </Button>
          </div>
        )}
      </DialogContent>
    </Dialog>
  );
}
