// components/subscription/DowngradeModal.tsx
'use client';

import { useState, useMemo, useEffect, useCallback, useRef } from 'react';
import { Modal, ModalBody } from '@/components/ui/Modal';
import {
  PLAN_DISPLAY_NAMES,
  PLAN_PRICES,
  TierName,
  BillingInterval,
  getAvailableIntervals,
  getFeaturesLost,
} from '@/lib/plan-features';
import { FeatureLossWarning } from './FeatureLossWarning';
import styles from './DowngradeModal.module.css';

interface PreviewData {
  proration: {
    amount: number;
    credit: number;
    dueNow: number;
  } | null;
  prorationUnavailable: boolean;
  featuresLost: string[];
}

interface DowngradeModalProps {
  isOpen: boolean;
  currentTier: TierName;
  currentBillingInterval: BillingInterval | null;
  targetTier: TierName;
  onConfirm: (billingInterval: BillingInterval, acknowledgeFeatureLoss: boolean) => Promise<void>;
  onCancel: () => void;
  isSubmitting: boolean;
  error: string | null;
}

/**
 * Modal for confirming subscription downgrade.
 * Shows feature loss warning, proration preview, and requires acknowledgment.
 * Uses the shared Modal component for consistent UX and accessibility.
 */
export function DowngradeModal({
  isOpen,
  currentTier,
  currentBillingInterval,
  targetTier,
  onConfirm,
  onCancel,
  isSubmitting,
  error,
}: DowngradeModalProps) {
  const availableIntervals = getAvailableIntervals(targetTier);
  const [selectedInterval, setSelectedInterval] = useState<BillingInterval>(
    availableIntervals.includes('monthly') ? 'monthly' : 'annual'
  );
  const [acknowledged, setAcknowledged] = useState(false);

  // Preview data state
  const [preview, setPreview] = useState<PreviewData | null>(null);
  const [previewLoading, setPreviewLoading] = useState(false);
  const [previewError, setPreviewError] = useState<string | null>(null);

  // AbortController for cancelling in-flight preview requests
  const abortControllerRef = useRef<AbortController | null>(null);

  // Calculate features lost (fallback if preview fails)
  const localFeaturesLost = useMemo(
    () => getFeaturesLost(currentTier, targetTier),
    [currentTier, targetTier]
  );

  // Use preview features if available, otherwise fall back to local calculation
  const featuresLost = preview?.featuresLost ?? localFeaturesLost;

  // Fetch preview when modal opens or billing interval changes
  const fetchPreview = useCallback(async () => {
    // Abort any in-flight request to prevent race conditions
    if (abortControllerRef.current) {
      abortControllerRef.current.abort();
    }

    const controller = new AbortController();
    abortControllerRef.current = controller;

    setPreviewLoading(true);
    setPreviewError(null);

    try {
      const response = await fetch(
        `/api/subscription/preview-change?targetTier=${targetTier}&billingInterval=${selectedInterval}`,
        { signal: controller.signal }
      );

      if (!response.ok) {
        const data = await response.json().catch(() => ({}));
        throw new Error(data.error || 'Failed to load preview');
      }

      const data = await response.json();
      setPreview({
        proration: data.proration,
        prorationUnavailable: data.prorationUnavailable ?? false,
        featuresLost: data.featuresLost ?? [],
      });
    } catch (err) {
      // Don't update state if the request was aborted (e.g., user switched intervals)
      if (err instanceof Error && err.name === 'AbortError') {
        return;
      }

      // Distinguish between network errors and API errors
      let errorMessage: string;
      if (err instanceof TypeError && err.message.includes('fetch')) {
        // Network error (no connection, DNS failure, etc.)
        errorMessage = 'Network error - please check your connection';
      } else if (err instanceof Error) {
        // API error (server returned error response)
        errorMessage = err.message;
      } else {
        errorMessage = 'Unable to load preview';
      }

      setPreviewError(errorMessage);
      setPreview(null);
    } finally {
      // Only update loading state if this request wasn't aborted
      if (!controller.signal.aborted) {
        setPreviewLoading(false);
      }
    }
  }, [targetTier, selectedInterval]);

  // Fetch preview when modal opens or interval changes (with debounce for interval changes)
  useEffect(() => {
    if (!isOpen) return;

    // Debounce interval changes to prevent API spam when rapidly toggling
    const debounceTimeout = setTimeout(() => {
      fetchPreview();
    }, 300); // 300ms debounce

    return () => clearTimeout(debounceTimeout);
  }, [isOpen, fetchPreview]);

  // Reset state and abort any pending requests when modal closes
  useEffect(() => {
    if (!isOpen) {
      // Abort any in-flight preview request
      if (abortControllerRef.current) {
        abortControllerRef.current.abort();
        abortControllerRef.current = null;
      }
      setAcknowledged(false);
      setPreview(null);
      setPreviewError(null);
      setPreviewLoading(false);
    }
  }, [isOpen]);

  const handleConfirm = () => {
    if (!acknowledged) return;
    onConfirm(selectedInterval, acknowledged);
  };

  // Format price display
  const formatPrice = (tier: TierName, interval: BillingInterval): string => {
    const pricing = PLAN_PRICES[tier];
    if (interval === 'monthly') {
      return pricing.monthly ? `$${pricing.monthly}/mo` : `$${pricing.annualMonthly}/mo`;
    }
    return `$${pricing.annual}/yr`;
  };

  // Get current price display
  // Default to annual if billing interval is null (loading or unknown state)
  const getCurrentPriceDisplay = (): string => {
    const pricing = PLAN_PRICES[currentTier];
    // Starter tier is annual-only; null defaults to annual as the safe assumption
    if (
      currentTier === 'starter' ||
      !currentBillingInterval ||
      currentBillingInterval === 'annual'
    ) {
      return `$${pricing.annual}/yr`;
    }
    return pricing.monthly ? `$${pricing.monthly}/mo` : `$${pricing.annualMonthly}/mo`;
  };

  // Format proration message
  const getProrationMessage = (): string => {
    if (previewLoading) {
      return 'Calculating credit...';
    }

    if (preview?.proration && !preview.prorationUnavailable) {
      const credit = preview.proration.credit;
      if (credit > 0) {
        return `You will receive a $${credit.toFixed(2)} credit for unused time on your current plan.`;
      }
      return 'Your subscription will be updated immediately with no additional charges.';
    }

    // Fallback message when preview unavailable
    return 'Your subscription will be updated immediately. Any unused time will be credited to your account.';
  };

  // Footer with action buttons
  const footer = (
    <div className={styles.actions}>
      <button className={styles.cancelButton} onClick={onCancel} disabled={isSubmitting}>
        Cancel
      </button>
      <button
        className={styles.confirmButton}
        onClick={handleConfirm}
        disabled={isSubmitting || !acknowledged || previewLoading}
      >
        {isSubmitting ? (
          <span className={styles.loading}>
            <span className={styles.spinner} />
            Processing...
          </span>
        ) : (
          'Confirm Downgrade'
        )}
      </button>
    </div>
  );

  return (
    <Modal
      isOpen={isOpen}
      onClose={onCancel}
      title="Confirm Downgrade"
      size="small"
      footer={footer}
    >
      <ModalBody>
        <p className={styles.description}>
          You are downgrading from <strong>{PLAN_DISPLAY_NAMES[currentTier]}</strong> to{' '}
          <strong>{PLAN_DISPLAY_NAMES[targetTier]}</strong>.
        </p>

        {/* Billing Interval Toggle */}
        {availableIntervals.length > 1 && (
          <div className={styles.intervalToggle}>
            <span className={styles.intervalLabel}>Billing:</span>
            <div className={styles.intervalButtons}>
              <button
                type="button"
                className={`${styles.intervalButton} ${selectedInterval === 'monthly' ? styles.intervalButtonActive : ''}`}
                onClick={() => setSelectedInterval('monthly')}
                disabled={previewLoading}
              >
                Monthly
              </button>
              <button
                type="button"
                className={`${styles.intervalButton} ${selectedInterval === 'annual' ? styles.intervalButtonActive : ''}`}
                onClick={() => setSelectedInterval('annual')}
                disabled={previewLoading}
              >
                Annual
              </button>
            </div>
          </div>
        )}

        {/* Price Comparison */}
        <div className={styles.priceComparison}>
          <div className={styles.priceItem}>
            <span className={styles.priceLabel}>Current</span>
            <span className={styles.priceValue}>{getCurrentPriceDisplay()}</span>
          </div>
          <div className={styles.priceArrow}>→</div>
          <div className={styles.priceItem}>
            <span className={styles.priceLabel}>New</span>
            <span className={styles.priceValueNew}>
              {formatPrice(targetTier, selectedInterval)}
            </span>
          </div>
        </div>

        {/* Feature Loss Warning */}
        {featuresLost.length > 0 && (
          <FeatureLossWarning features={featuresLost} className={styles.featureWarning} />
        )}

        {/* Proration Notice - now with actual values from preview */}
        <p className={styles.prorationNotice}>
          {previewLoading && <span className={styles.miniSpinner} />}
          {getProrationMessage()}
        </p>

        {/* Preview Error (non-blocking warning with retry) */}
        {previewError && !previewLoading && (
          <div className={styles.previewWarning}>
            <span>
              Unable to calculate exact credit. The downgrade will still process correctly.
            </span>
            <button
              type="button"
              onClick={fetchPreview}
              className={styles.retryButton}
              aria-label="Retry loading preview"
            >
              Retry
            </button>
          </div>
        )}

        {/* Acknowledgment Checkbox */}
        <label className={styles.acknowledgment}>
          <input
            type="checkbox"
            checked={acknowledged}
            onChange={(e) => setAcknowledged(e.target.checked)}
            className={styles.checkbox}
          />
          <span className={styles.checkboxLabel}>
            I understand that I will lose access to the features listed above and this change takes
            effect immediately.
          </span>
        </label>

        {/* Error Message */}
        {error && <div className={styles.error}>{error}</div>}
      </ModalBody>
    </Modal>
  );
}

export default DowngradeModal;
