import axios from 'axios';
import { AlertTriangle, ArrowRight, CheckCircle2, Loader2, XCircle } from 'lucide-react';
import { toast } from 'sonner';

import { useEffect, useState } from 'react';

import { router } from '@inertiajs/react';

import { Alert, AlertDescription, AlertTitle } from '@/Components/ui/alert';
import { Button } from '@/Components/ui/button';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from '@/Components/ui/dialog';
import { LoadingButton } from '@/Components/ui/loading-button';
import { trackEvent } from '@/lib/analytics';
import { SWAP_ABANDONED, SWAP_CONFIRMED, SWAP_CONFIRMATION_SHOWN } from '@/lib/event-catalog';
import { formatCurrency } from '@/lib/format';

interface TierData {
  name: string;
  features: string[];
  limits: Record<string, number | null>;
  price: number | null;
  price_annual: number | null;
}

interface LimitComparisonItem {
  label: string;
  current: number | null;
  new: number | null;
}

interface PreviewResponse {
  current_plan: string;
  new_plan: string;
  current_price: string;
  new_price: string;
  immediate_charge: number | null;
  proration_date: string;
  is_upgrade: boolean;
  warnings: string[];
  limit_comparison?: LimitComparisonItem[];
  current_usage?: {
    sites: number;
    drafts_this_month: number;
  };
  target_limits?: {
    max_sites: number | null;
    max_drafts: number | null;
  };
  limit_violations?: string[];
}

interface SwapConfirmationDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  currentPlan: string;
  newPlan: string;
  newPriceId: string;
  tiers: Record<string, TierData>;
  /** Hint the downgrade direction before the preview loads (BILL-021-01). */
  isDowngrade?: boolean;
}

export function SwapConfirmationDialog({
  open,
  onOpenChange,
  currentPlan,
  newPlan,
  newPriceId,
  tiers,
  isDowngrade: isDowngradeHint = false,
}: SwapConfirmationDialogProps) {
  const [preview, setPreview] = useState<PreviewResponse | null>(null);
  const [loading, setLoading] = useState(false);
  const [swapping, setSwapping] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const currentTier = tiers[currentPlan];
  const newTier = tiers[newPlan];

  useEffect(() => {
    if (!open || !newPriceId) return;

    setLoading(true);
    setError(null);

    trackEvent(SWAP_CONFIRMATION_SHOWN, { current_plan: currentPlan, new_plan: newPlan });

    // BILL-008: Use GET with query params — previewSwap reads from $request->query()
    axios
      .get<PreviewResponse>(route('billing.preview-swap'), { params: { price_id: newPriceId } })
      .then((res) => setPreview(res.data))
      .catch(() => setError('Unable to load plan comparison. Please try again.'))
      .finally(() => setLoading(false));
  }, [open, newPriceId, currentPlan, newPlan]);

  const handleConfirm = () => {
    setSwapping(true);
    trackEvent(SWAP_CONFIRMED, { current_plan: currentPlan, new_plan: newPlan });
    router.post(
      route('billing.swap'),
      { price_id: newPriceId },
      {
        onFinish: () => setSwapping(false),
        onError: () => {
          toast.error('Failed to change plan. Please try again.');
          setSwapping(false);
        },
      },
    );
  };

  const handleCancel = () => {
    trackEvent(SWAP_ABANDONED, { current_plan: currentPlan, new_plan: newPlan });
    onOpenChange(false);
  };

  const getFeatureDiff = () => {
    if (!currentTier || !newTier) return { gained: [], lost: [] };
    const currentFeatures = new Set(currentTier.features);
    const newFeatures = new Set(newTier.features);
    const gained = newTier.features.filter((f) => !currentFeatures.has(f));
    const lost = currentTier.features.filter((f) => !newFeatures.has(f));
    return { gained, lost };
  };

  const { gained, lost } = getFeatureDiff();
  // Use server preview when available; fall back to the caller-provided hint while loading.
  const isDowngrade = preview ? !preview.is_upgrade : isDowngradeHint;

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent className="sm:max-w-lg">
        <DialogHeader>
          <DialogTitle>{isDowngrade ? 'Confirm Downgrade' : 'Confirm Plan Change'}</DialogTitle>
          <DialogDescription>
            {currentTier?.name ?? currentPlan} <ArrowRight className="inline h-4 w-4 mx-1" />{' '}
            {newTier?.name ?? newPlan}
          </DialogDescription>
        </DialogHeader>

        {loading ? (
          <div className="flex items-center justify-center py-8">
            <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
            <span className="ml-2 text-sm text-muted-foreground">Loading comparison...</span>
          </div>
        ) : error ? (
          <Alert variant="destructive">
            <AlertTriangle className="h-4 w-4" />
            <AlertDescription>{error}</AlertDescription>
          </Alert>
        ) : (
          <div className="space-y-4 py-2">
            {preview && preview.immediate_charge !== null && (
              <div className="flex items-center justify-between p-3 bg-accent/50 rounded-lg">
                <span className="text-sm font-medium">Prorated charge</span>
                <span className="text-sm font-semibold">
                  {formatCurrency(preview.immediate_charge)}
                </span>
              </div>
            )}

            {gained.length > 0 && (
              <div className="space-y-1">
                <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
                  You'll gain
                </p>
                {gained.map((f) => (
                  <div key={f} className="flex items-start gap-2 text-sm">
                    <CheckCircle2 className="h-4 w-4 text-success mt-0.5 shrink-0" />
                    <span>{f}</span>
                  </div>
                ))}
              </div>
            )}

            {lost.length > 0 && (
              <div className="space-y-1">
                <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
                  You'll lose
                </p>
                {lost.map((f) => (
                  <div key={f} className="flex items-start gap-2 text-sm">
                    <XCircle className="h-4 w-4 text-destructive mt-0.5 shrink-0" />
                    <span>{f}</span>
                  </div>
                ))}
              </div>
            )}

            {isDowngrade && preview?.limit_comparison && preview.limit_comparison.length > 0 && (
              <div className="space-y-1">
                <p className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
                  Limit changes
                </p>
                <div className="rounded-md border border-destructive/30 overflow-hidden">
                  <table className="w-full text-sm">
                    <thead>
                      <tr className="bg-destructive/5">
                        <th className="text-left px-3 py-2 font-medium text-muted-foreground">Limit</th>
                        <th className="text-right px-3 py-2 font-medium text-muted-foreground">Current</th>
                        <th className="text-right px-3 py-2 font-medium text-destructive">After downgrade</th>
                      </tr>
                    </thead>
                    <tbody>
                      {preview.limit_comparison.map((item) => (
                        <tr key={item.label} className="border-t border-border">
                          <td className="px-3 py-2">{item.label}</td>
                          <td className="px-3 py-2 text-right text-muted-foreground">
                            {item.current === null ? 'Unlimited' : item.current}
                          </td>
                          <td className="px-3 py-2 text-right font-semibold text-destructive">
                            {item.new === null ? 'Unlimited' : item.new}
                          </td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              </div>
            )}

            {preview?.warnings && preview.warnings.length > 0 && (
              <Alert variant={isDowngrade ? 'destructive' : undefined} className={isDowngrade ? undefined : 'border-amber-200 bg-amber-50 dark:border-amber-800 dark:bg-amber-950'}>
                <AlertTriangle className={`h-4 w-4 ${isDowngrade ? '' : 'text-amber-600 dark:text-amber-400'}`} />
                <AlertTitle className={isDowngrade ? undefined : 'text-amber-900 dark:text-amber-100'}>Important</AlertTitle>
                <AlertDescription className={isDowngrade ? undefined : 'text-amber-800 dark:text-amber-200'}>
                  <ul className="list-disc pl-4 space-y-1">
                    {preview.warnings.map((w) => (
                      <li key={w} className="text-sm">
                        {w}
                      </li>
                    ))}
                  </ul>
                </AlertDescription>
              </Alert>
            )}

            {preview?.limit_violations && preview.limit_violations.length > 0 && (
              <Alert variant="destructive">
                <AlertTriangle className="h-4 w-4" />
                <AlertTitle>Usage exceeds target plan limits</AlertTitle>
                <AlertDescription>
                  <ul className="list-disc pl-4 space-y-1">
                    {preview.limit_violations.map((v) => (
                      <li key={v} className="text-sm">
                        {v}
                      </li>
                    ))}
                  </ul>
                </AlertDescription>
              </Alert>
            )}
          </div>
        )}

        <DialogFooter>
          <Button variant="outline" onClick={handleCancel} disabled={swapping}>
            Cancel
          </Button>
          <LoadingButton
            variant={isDowngrade ? 'destructive' : 'default'}
            onClick={handleConfirm}
            loading={swapping}
            loadingText="Changing plan..."
            disabled={loading || !!error}
          >
            {isDowngrade ? 'Confirm Downgrade' : 'Confirm Upgrade'}
          </LoadingButton>
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
}
