import React from 'react';
import { Sheet } from '@tamagui/sheet';
import { YStack, XStack } from '@tamagui/stacks';
import { SizableText as Text } from '@tamagui/text';
import { Button } from '@tamagui/button';
import { Copy, Download, Loader2, MessageSquare, RefreshCcw, Share2, Sparkles, Wand2, X } from 'lucide-react';
import { useTranslation } from '@/shared/guest/i18n/useTranslation';
import { useGuestThemeVariant } from '../lib/guestTheme';
import {
  createGuestAiEdit,
  fetchGuestAiEditStatus,
  fetchGuestAiStyles,
  type GuestAiEditRequest,
  type GuestAiStyle,
} from '../services/aiEditsApi';
import type { ApiError } from '../services/apiClient';
import { pushGuestToast } from '../lib/toast';

type AiMagicEditSheetProps = {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  eventToken: string | null;
  photoId: number | null;
  originalImageUrl: string | null;
};

const POLLABLE_STATUSES = new Set(['queued', 'processing']);
const MAX_POLL_ATTEMPTS = 72;
const POLL_INTERVAL_MS = 2500;

function resolveErrorMessage(error: unknown, fallback: string): string {
  const apiError = error as ApiError;

  if (typeof apiError?.message === 'string' && apiError.message.trim() !== '') {
    return apiError.message;
  }

  return fallback;
}

function buildIdempotencyKey(photoId: number): string {
  if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
    return `guest-ai-${photoId}-${crypto.randomUUID()}`;
  }

  return `guest-ai-${photoId}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
}

function resolveOutputUrl(request: GuestAiEditRequest | null): string | null {
  if (!request || !Array.isArray(request.outputs)) {
    return null;
  }

  const normalizeStorageUrl = (storagePath?: string | null): string | null => {
    if (!storagePath || typeof storagePath !== 'string') {
      return null;
    }

    if (/^https?:/i.test(storagePath)) {
      return storagePath;
    }

    const cleanPath = storagePath.replace(/^\/+/g, '');
    if (cleanPath.startsWith('storage/')) {
      return `/${cleanPath}`;
    }

    return `/storage/${cleanPath}`;
  };

  const primary = request.outputs.find(
    (output) =>
      output.is_primary
      && (
        (typeof output.provider_url === 'string' && output.provider_url)
        || (typeof output.storage_path === 'string' && output.storage_path)
      )
  );
  if (primary?.provider_url) {
    return primary.provider_url;
  }
  if (primary?.storage_path) {
    return normalizeStorageUrl(primary.storage_path);
  }

  const first = request.outputs.find(
    (output) =>
      (typeof output.provider_url === 'string' && output.provider_url)
      || (typeof output.storage_path === 'string' && output.storage_path)
  );

  if (first?.provider_url) {
    return first.provider_url;
  }

  return normalizeStorageUrl(first?.storage_path);
}

export default function AiMagicEditSheet({
  open,
  onOpenChange,
  eventToken,
  photoId,
  originalImageUrl,
}: AiMagicEditSheetProps) {
  const { t } = useTranslation();
  const { isDark } = useGuestThemeVariant();
  const mutedSurface = isDark ? 'rgba(255, 255, 255, 0.08)' : 'rgba(15, 23, 42, 0.06)';
  const mutedBorder = isDark ? 'rgba(255, 255, 255, 0.2)' : 'rgba(15, 23, 42, 0.12)';

  const [styles, setStyles] = React.useState<GuestAiStyle[]>([]);
  const [stylesLoading, setStylesLoading] = React.useState(false);
  const [stylesError, setStylesError] = React.useState<string | null>(null);
  const [selectedStyleKey, setSelectedStyleKey] = React.useState<string | null>(null);
  const [request, setRequest] = React.useState<GuestAiEditRequest | null>(null);
  const [requestError, setRequestError] = React.useState<string | null>(null);
  const [submitting, setSubmitting] = React.useState(false);
  const [isOnline, setIsOnline] = React.useState<boolean>(() => {
    if (typeof navigator === 'undefined') {
      return true;
    }

    return navigator.onLine;
  });
  const pollAttemptsRef = React.useRef(0);

  const selectedStyle = React.useMemo(() => {
    if (!selectedStyleKey) {
      return null;
    }

    return styles.find((style) => style.key === selectedStyleKey) ?? null;
  }, [selectedStyleKey, styles]);

  const outputUrl = React.useMemo(() => resolveOutputUrl(request), [request]);

  const resetRequestState = React.useCallback(() => {
    setRequest(null);
    setRequestError(null);
    setSubmitting(false);
    pollAttemptsRef.current = 0;
  }, []);

  const loadStyles = React.useCallback(async () => {
    if (!eventToken || !photoId) {
      return;
    }

    setStylesLoading(true);
    setStylesError(null);

    try {
      const payload = await fetchGuestAiStyles(eventToken);
      const nextStyles = Array.isArray(payload.data) ? payload.data : [];
      setStyles(nextStyles);
      if (nextStyles.length > 0) {
        setSelectedStyleKey(nextStyles[0]?.key ?? null);
      } else {
        setSelectedStyleKey(null);
        setStylesError(t('galleryPage.lightbox.aiMagicEditNoStyles', 'No AI styles are currently available.'));
      }
    } catch (error) {
      setStyles([]);
      setSelectedStyleKey(null);
      setStylesError(resolveErrorMessage(error, t('galleryPage.lightbox.aiMagicEditStylesFailed', 'AI styles could not be loaded.')));
    } finally {
      setStylesLoading(false);
    }
  }, [eventToken, photoId, t]);

  React.useEffect(() => {
    if (!open) {
      resetRequestState();
      return;
    }

    if (!eventToken || !photoId) {
      setStyles([]);
      setSelectedStyleKey(null);
      setStylesError(t('galleryPage.lightbox.aiMagicEditUnavailable', 'AI Magic Edit is currently unavailable.'));
      return;
    }

    resetRequestState();
    void loadStyles();
  }, [eventToken, loadStyles, open, photoId, resetRequestState, t]);

  React.useEffect(() => {
    const handleOnline = () => {
      setIsOnline(true);
    };
    const handleOffline = () => {
      setIsOnline(false);
    };

    window.addEventListener('online', handleOnline);
    window.addEventListener('offline', handleOffline);

    return () => {
      window.removeEventListener('online', handleOnline);
      window.removeEventListener('offline', handleOffline);
    };
  }, []);

  React.useEffect(() => {
    if (!open || !eventToken || !request || !POLLABLE_STATUSES.has(request.status) || !isOnline) {
      return;
    }

    let cancelled = false;
    const timer = window.setTimeout(async () => {
      if (pollAttemptsRef.current >= MAX_POLL_ATTEMPTS) {
        setRequestError(t('galleryPage.lightbox.aiMagicEditPollingTimeout', 'AI generation took too long. Please try again.'));
        return;
      }

      pollAttemptsRef.current += 1;

      try {
        const payload = await fetchGuestAiEditStatus(eventToken, request.id);
        if (cancelled) {
          return;
        }

        setRequest(payload.data);
        if (payload.data.status === 'succeeded' && !resolveOutputUrl(payload.data)) {
          setRequestError(t('galleryPage.lightbox.aiMagicEditResultMissing', 'The AI result could not be loaded.'));
        }
      } catch (error) {
        if (cancelled) {
          return;
        }

        if (typeof navigator !== 'undefined' && !navigator.onLine) {
          setIsOnline(false);
          return;
        }

        setRequestError(resolveErrorMessage(error, t('galleryPage.lightbox.aiMagicEditStatusFailed', 'AI status could not be refreshed.')));
      }
    }, POLL_INTERVAL_MS);

    return () => {
      cancelled = true;
      window.clearTimeout(timer);
    };
  }, [eventToken, isOnline, open, request, t]);

  const startAiEdit = React.useCallback(async () => {
    if (!eventToken || !photoId || !selectedStyleKey) {
      return;
    }

    setSubmitting(true);
    setRequestError(null);

    try {
      const payload = await createGuestAiEdit(eventToken, photoId, {
        style_key: selectedStyleKey,
        idempotency_key: buildIdempotencyKey(photoId),
        metadata: {
          client: 'guest-v2',
          entrypoint: 'lightbox',
        },
      });

      pollAttemptsRef.current = 0;
      setRequest(payload.data);
      if (payload.data.status === 'succeeded' && !resolveOutputUrl(payload.data)) {
        setRequestError(t('galleryPage.lightbox.aiMagicEditResultMissing', 'The AI result could not be loaded.'));
      }
    } catch (error) {
      setRequestError(resolveErrorMessage(error, t('galleryPage.lightbox.aiMagicEditStartFailed', 'AI edit could not be started.')));
    } finally {
      setSubmitting(false);
    }
  }, [eventToken, photoId, selectedStyleKey, t]);

  const downloadGenerated = React.useCallback(() => {
    if (!outputUrl || !request?.id) {
      return;
    }

    const link = document.createElement('a');
    link.href = outputUrl;
    link.download = `ai-edit-${request.id}.jpg`;
    link.rel = 'noreferrer';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }, [outputUrl, request?.id]);

  const copyGeneratedLink = React.useCallback(async () => {
    if (!outputUrl) {
      return;
    }

    try {
      await navigator.clipboard?.writeText(outputUrl);
      pushGuestToast({ text: t('share.copySuccess', 'Link copied!') });
    } catch (error) {
      console.error('Copy generated link failed', error);
      pushGuestToast({ text: t('share.copyError', 'Link could not be copied.'), type: 'error' });
    }
  }, [outputUrl, t]);

  const shareGeneratedNative = React.useCallback(() => {
    if (!outputUrl) {
      return;
    }

    const shareData: ShareData = {
      title: t('galleryPage.lightbox.aiMagicEditShareTitle', 'AI Magic Edit'),
      text: t('galleryPage.lightbox.aiMagicEditShareText', 'Check out my AI edited photo!'),
      url: outputUrl,
    };

    if (navigator.share && (!navigator.canShare || navigator.canShare(shareData))) {
      navigator.share(shareData).catch(() => undefined);
      return;
    }

    void copyGeneratedLink();
  }, [copyGeneratedLink, outputUrl, t]);

  const shareGeneratedWhatsApp = React.useCallback(() => {
    if (!outputUrl) {
      return;
    }

    const text = t('galleryPage.lightbox.aiMagicEditShareText', 'Check out my AI edited photo!');
    const waUrl = `https://wa.me/?text=${encodeURIComponent(`${text} ${outputUrl}`)}`;
    window.open(waUrl, '_blank', 'noopener');
  }, [outputUrl, t]);

  const shareGeneratedMessages = React.useCallback(() => {
    if (!outputUrl) {
      return;
    }

    const text = t('galleryPage.lightbox.aiMagicEditShareText', 'Check out my AI edited photo!');
    const smsUrl = `sms:?&body=${encodeURIComponent(`${text} ${outputUrl}`)}`;
    window.open(smsUrl, '_blank', 'noopener');
  }, [outputUrl, t]);

  const isProcessing = Boolean(request && POLLABLE_STATUSES.has(request.status));
  const isDone = request?.status === 'succeeded' && Boolean(outputUrl);

  const content = (
    <YStack gap="$3">
      <XStack alignItems="center" justifyContent="space-between" gap="$2">
        <XStack alignItems="center" gap="$2">
          <Wand2 size={18} color={isDark ? '#F8FAFF' : '#0F172A'} />
          <YStack>
            <Text fontSize="$4" fontWeight="$8">
              {t('galleryPage.lightbox.aiMagicEdit', 'AI Magic Edit')}
            </Text>
            <Text fontSize="$1" color="$color" opacity={0.7}>
              {t('galleryPage.lightbox.aiMagicEditSubtitle', 'Choose a style and generate an AI version.')}
            </Text>
          </YStack>
        </XStack>
        <Button
          size="$3"
          circular
          backgroundColor={mutedSurface}
          borderWidth={1}
          borderColor={mutedBorder}
          onPress={() => onOpenChange(false)}
          aria-label={t('common.actions.close', 'Close')}
        >
          <X size={16} color={isDark ? '#F8FAFF' : '#0F172A'} />
        </Button>
      </XStack>

      {stylesLoading ? (
        <XStack alignItems="center" gap="$2" paddingVertical="$2">
          <Loader2 size={16} className="animate-spin" color={isDark ? '#F8FAFF' : '#0F172A'} />
          <Text fontSize="$2" color="$color" opacity={0.8}>
            {t('galleryPage.lightbox.aiMagicEditLoadingStyles', 'Loading styles...')}
          </Text>
        </XStack>
      ) : null}

      {stylesError ? (
        <YStack gap="$2" padding="$3" borderRadius="$card" backgroundColor={mutedSurface} borderWidth={1} borderColor={mutedBorder}>
          <Text fontSize="$2" color="#FCA5A5">{stylesError}</Text>
          <XStack gap="$2">
            <Button onPress={() => void loadStyles()} backgroundColor={mutedSurface} borderWidth={1} borderColor={mutedBorder}>
              <XStack alignItems="center" gap="$1.5">
                <RefreshCcw size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                <Text fontSize="$2" fontWeight="$6">{t('common.actions.retry', 'Retry')}</Text>
              </XStack>
            </Button>
          </XStack>
        </YStack>
      ) : null}

      {!stylesLoading && !stylesError && !request ? (
        <YStack gap="$3">
          <YStack gap="$2">
            <Text fontSize="$2" fontWeight="$7">
              {t('galleryPage.lightbox.aiMagicEditSelectStyle', 'Select style')}
            </Text>
            <XStack gap="$2" flexWrap="wrap">
              {styles.map((style) => {
                const selected = style.key === selectedStyleKey;

                return (
                  <Button
                    key={style.key}
                    size="$3"
                    backgroundColor={selected ? '$primary' : mutedSurface}
                    borderWidth={1}
                    borderColor={selected ? '$primary' : mutedBorder}
                    onPress={() => setSelectedStyleKey(style.key)}
                  >
                    <Text fontSize="$2" fontWeight="$6" color={selected ? '#FFFFFF' : undefined}>
                      {style.name}
                    </Text>
                  </Button>
                );
              })}
            </XStack>
            {selectedStyle?.description ? (
              <Text fontSize="$1" color="$color" opacity={0.75}>
                {selectedStyle.description}
              </Text>
            ) : null}
          </YStack>

          {originalImageUrl ? (
            <YStack gap="$1">
              <Text fontSize="$1" color="$color" opacity={0.7}>
                {t('galleryPage.lightbox.aiMagicEditOriginalPreview', 'Original photo')}
              </Text>
              <img
                src={originalImageUrl}
                alt={t('galleryPage.lightbox.aiMagicEditOriginalAlt', 'Original photo')}
                style={{
                  width: '100%',
                  maxHeight: 180,
                  objectFit: 'cover',
                  borderRadius: 12,
                  border: `1px solid ${mutedBorder}`,
                }}
              />
            </YStack>
          ) : null}

          <Button
            backgroundColor="$primary"
            onPress={() => void startAiEdit()}
            disabled={!selectedStyleKey || submitting}
          >
            <XStack alignItems="center" gap="$2">
              {submitting ? <Loader2 size={14} className="animate-spin" color="#FFFFFF" /> : <Sparkles size={14} color="#FFFFFF" />}
              <Text fontSize="$2" fontWeight="$7" color="#FFFFFF">
                {submitting
                  ? t('galleryPage.lightbox.aiMagicEditStarting', 'Starting...')
                  : t('galleryPage.lightbox.aiMagicEditGenerate', 'Generate AI edit')}
              </Text>
            </XStack>
          </Button>
        </YStack>
      ) : null}

      {request ? (
        <YStack gap="$3">
          <YStack gap="$1">
            <Text fontSize="$2" fontWeight="$7">
              {request.style?.name ?? t('galleryPage.lightbox.aiMagicEditResultTitle', 'Result')}
            </Text>
            <Text fontSize="$1" color="$color" opacity={0.7}>
              {isProcessing
                ? t('galleryPage.lightbox.aiMagicEditProcessing', 'Generating your AI edit...')
                : request.status === 'succeeded'
                  ? t('galleryPage.lightbox.aiMagicEditReady', 'Your AI edit is ready.')
                  : t('galleryPage.lightbox.aiMagicEditFailed', 'AI edit could not be completed.')}
            </Text>
          </YStack>

          {isProcessing ? (
            <XStack alignItems="center" gap="$2">
              <Loader2 size={16} className="animate-spin" color={isDark ? '#F8FAFF' : '#0F172A'} />
              <Text fontSize="$2" color="$color" opacity={0.8}>
                {t('galleryPage.lightbox.aiMagicEditProcessingHint', 'This can take a few seconds.')}
              </Text>
            </XStack>
          ) : null}
          {isProcessing && !isOnline ? (
            <Text fontSize="$2" color="$color" opacity={0.8}>
              {t(
                'galleryPage.lightbox.aiMagicEditOfflineHint',
                'You are offline. Status updates resume automatically when connection is back.'
              )}
            </Text>
          ) : null}

          {isDone && originalImageUrl ? (
            <XStack gap="$2" flexWrap="wrap">
              <YStack flex={1} minWidth={150} gap="$1">
                <Text fontSize="$1" color="$color" opacity={0.7}>
                  {t('galleryPage.lightbox.aiMagicEditOriginalLabel', 'Original')}
                </Text>
                <img
                  src={originalImageUrl}
                  alt={t('galleryPage.lightbox.aiMagicEditOriginalAlt', 'Original photo')}
                  style={{
                    width: '100%',
                    maxHeight: 220,
                    objectFit: 'cover',
                    borderRadius: 12,
                    border: `1px solid ${mutedBorder}`,
                  }}
                />
              </YStack>
              <YStack flex={1} minWidth={150} gap="$1">
                <Text fontSize="$1" color="$color" opacity={0.7}>
                  {t('galleryPage.lightbox.aiMagicEditGeneratedLabel', 'AI result')}
                </Text>
                <img
                  src={outputUrl}
                  alt={t('galleryPage.lightbox.aiMagicEditGeneratedAlt', 'AI generated photo')}
                  style={{
                    width: '100%',
                    maxHeight: 220,
                    objectFit: 'cover',
                    borderRadius: 12,
                    border: `1px solid ${mutedBorder}`,
                  }}
                />
              </YStack>
            </XStack>
          ) : null}

          {requestError ? (
            <Text fontSize="$2" color="#FCA5A5">{requestError}</Text>
          ) : null}

          {(request.status === 'failed' || request.status === 'blocked' || request.status === 'canceled') && request.failure_message ? (
            <Text fontSize="$2" color="#FCA5A5">{request.failure_message}</Text>
          ) : null}

          <XStack gap="$2" flexWrap="wrap" justifyContent="flex-end">
            <Button
              backgroundColor={mutedSurface}
              borderWidth={1}
              borderColor={mutedBorder}
              onPress={resetRequestState}
            >
              <XStack alignItems="center" gap="$1.5">
                <RefreshCcw size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                <Text fontSize="$2" fontWeight="$6">
                  {t('galleryPage.lightbox.aiMagicEditTryAnother', 'Try another style')}
                </Text>
              </XStack>
            </Button>
            {isDone ? (
              <Button backgroundColor="$primary" onPress={downloadGenerated}>
                <XStack alignItems="center" gap="$1.5">
                  <Download size={14} color="#FFFFFF" />
                  <Text fontSize="$2" fontWeight="$7" color="#FFFFFF">
                    {t('common.actions.download', 'Download')}
                  </Text>
                </XStack>
              </Button>
            ) : null}
          </XStack>
          {isDone ? (
            <XStack gap="$2" flexWrap="wrap">
              <Button
                backgroundColor={mutedSurface}
                borderWidth={1}
                borderColor={mutedBorder}
                onPress={shareGeneratedNative}
              >
                <XStack alignItems="center" gap="$1.5">
                  <Share2 size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                  <Text fontSize="$2" fontWeight="$6">
                    {t('share.button', 'Share')}
                  </Text>
                </XStack>
              </Button>
              <Button
                backgroundColor={mutedSurface}
                borderWidth={1}
                borderColor={mutedBorder}
                onPress={shareGeneratedWhatsApp}
              >
                <XStack alignItems="center" gap="$1.5">
                  <MessageSquare size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                  <Text fontSize="$2" fontWeight="$6">
                    {t('share.whatsapp', 'WhatsApp')}
                  </Text>
                </XStack>
              </Button>
              <Button
                backgroundColor={mutedSurface}
                borderWidth={1}
                borderColor={mutedBorder}
                onPress={shareGeneratedMessages}
              >
                <XStack alignItems="center" gap="$1.5">
                  <MessageSquare size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                  <Text fontSize="$2" fontWeight="$6">
                    {t('share.imessage', 'Messages')}
                  </Text>
                </XStack>
              </Button>
              <Button
                backgroundColor={mutedSurface}
                borderWidth={1}
                borderColor={mutedBorder}
                onPress={() => void copyGeneratedLink()}
              >
                <XStack alignItems="center" gap="$1.5">
                  <Copy size={14} color={isDark ? '#F8FAFF' : '#0F172A'} />
                  <Text fontSize="$2" fontWeight="$6">
                    {t('share.copyLink', 'Copy link')}
                  </Text>
                </XStack>
              </Button>
            </XStack>
          ) : null}
        </YStack>
      ) : null}
    </YStack>
  );

  return (
    <Sheet open={open} onOpenChange={onOpenChange} snapPoints={[88]} position={open ? 0 : -1} modal>
      <Sheet.Overlay {...({ backgroundColor: isDark ? 'rgba(15, 23, 42, 0.6)' : 'rgba(15, 23, 42, 0.35)' } as any)} />
      <Sheet.Frame padding="$4" backgroundColor="$surface" borderTopLeftRadius="$6" borderTopRightRadius="$6">
        <Sheet.Handle height={5} width={52} backgroundColor="#CBD5E1" borderRadius={999} marginBottom="$3" />
        <YStack style={{ maxHeight: '82vh', overflowY: 'auto' }}>
          {content}
        </YStack>
      </Sheet.Frame>
    </Sheet>
  );
}
