
import { useMemo, useState } from 'preact/hooks';
import { registerModule, type AsukaModuleComponent } from '../../core/modules';
import { getI18n } from '../../core/i18n';
import { useT } from '../../hooks/useT';
import { useAsukaStore } from '../../store/asukaStore';
import { DEFAULT_PERMISSIONS } from '../../core/permissions';
import { Card, CardContent } from '../core/Card';
import { Button } from '../core/Button';

const STYLE_OPTIONS = [
  { value: '', label: 'Default', labelKey: 'image.aiStyleDefault' },
  { value: 'photorealistic', label: 'Photorealistic', labelKey: 'image.aiStylePhotorealistic' },
  { value: 'illustration', label: 'Illustration', labelKey: 'image.aiStyleIllustration' },
  { value: 'flat-design', label: 'Flat design', labelKey: 'image.aiStyleFlatDesign' },
  { value: '3d-render', label: '3D render', labelKey: 'image.aiStyle3dRender' },
  { value: 'watercolor', label: 'Watercolor', labelKey: 'image.aiStyleWatercolor' },
];

const RATIO_OPTIONS = ['1:1', '4:5', '3:4', '16:9', '9:16'];

const AiSpinner = ({ className = '' }: { className?: string }) => (
  <span
    className={`ask-inline-block ask-h-3 ask-w-3 ask-shrink-0 ask-animate-spin ask-rounded-full ask-border-2 ask-border-current ask-border-t-transparent ${className}`}
    aria-hidden="true"
  />
);

type GeneratedImageItem = {
  id: string;
  url: string;
  revisedPrompt?: string;
  metadata?: Record<string, unknown>;
};

function createResultId(index: number): string {
  return `ai-${Date.now()}-${index}-${Math.random().toString(36).slice(2)}`;
}

export const AiTextToImagePanel: AsukaModuleComponent = ({ context }) => {
  const t = useT();
  const engine = context.getEngine?.() ?? null;
  const permissions = useAsukaStore((s: any) => s.permissions ?? DEFAULT_PERMISSIONS);
  const canUseLicenseFeature = useAsukaStore((s: any) => s.canUseLicenseFeature);
  const aiRuntime = useAsukaStore((s: any) => s.aiRuntime);
  const licenseResolutionTick = useAsukaStore((s: any) => s.licenseResolution?.resolvedAt ?? '');
  const aiQuota = useMemo(() => {
    void licenseResolutionTick;
    return aiRuntime?.getQuota?.() ?? null;
  }, [aiRuntime, licenseResolutionTick]);

  const [prompt, setPrompt] = useState('');
  const [negativePrompt, setNegativePrompt] = useState('');
  const [stylePreset, setStylePreset] = useState('');
  const [aspectRatio, setAspectRatio] = useState('1:1');
  const [submitting, setSubmitting] = useState(false);
  const [status, setStatus] = useState<'idle' | 'loading' | 'success'>('idle');
  const [error, setError] = useState<string | null>(null);
  const [results, setResults] = useState<GeneratedImageItem[]>([]);

  const isAvailable = canUseLicenseFeature?.('aiCredits') !== false;
  const quotaReached = aiQuota?.reached === true;

  const blobToDataUrl = async (blob: Blob): Promise<string> => {
    return await new Promise<string>((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => resolve(String(reader.result || ''));
      reader.onerror = () => reject(reader.error || new Error('Could not read generated image blob.'));
      reader.readAsDataURL(blob);
    });
  };

  const makeGeneratedImageSourceCanvasSafe = async (src: string): Promise<string> => {
    const value = String(src || '').trim();
    if (!value) throw new Error('The AI provider returned an empty image source.');
    if (/^data:/i.test(value)) return value;
    try {
      const response = await fetch(value, { mode: 'cors' });
      if (!response.ok) throw new Error(`Image fetch failed with ${response.status}`);
      const blob = await response.blob();
      return await blobToDataUrl(blob);
    } catch {
      // Keep the thumbnail URL usable in the panel, but adding to the canvas may still require Symfony CORS/proxy.
      return value;
    }
  };

  const resolveResultUrl = async (result: any): Promise<string> => {
    if (typeof result?.dataUrl === 'string' && result.dataUrl) return result.dataUrl;
    if (result?.blob instanceof Blob) return await blobToDataUrl(result.blob);
    if (typeof result?.url === 'string' && result.url) return await makeGeneratedImageSourceCanvasSafe(result.url);
    throw new Error('The AI provider returned no usable image.');
  };

  const resolveResultItems = async (result: any): Promise<GeneratedImageItem[]> => {
    const rawItems = Array.isArray(result?.images) ? result.images : [result];
    const items = await Promise.all(rawItems.map(async (item: any, index: number) => {
      const url = await resolveResultUrl(item);
      return {
        id: createResultId(index),
        url,
        revisedPrompt: String(item?.revisedPrompt ?? result?.revisedPrompt ?? '').trim() || undefined,
        metadata: item?.metadata ?? result?.metadata,
      } as GeneratedImageItem;
    }));
    return items.filter((item) => typeof item.url === 'string' && item.url.trim().length > 0);
  };

  const handleGenerate = async () => {
    setError(null);
    setStatus('idle');
    if (!isAvailable) {
      setError(t('license.aiCreditsRequired', 'A Pro or Agency plan is required to use AI image generation.'));
      return;
    }
    if (quotaReached) {
      setError(t('license.aiCreditsReached', 'No AI credits are remaining for the current period.'));
      return;
    }
    const cleanedPrompt = String(prompt ?? '').trim();
    if (!cleanedPrompt) {
      setError(t('image.aiPromptRequired', 'Write a prompt before generating an image.'));
      return;
    }
    try {
      setSubmitting(true);
      setStatus('loading');
      const result = await aiRuntime?.textToImage?.generate?.({
        prompt: cleanedPrompt,
        negativePrompt: String(negativePrompt ?? '').trim() || undefined,
        aspectRatio,
        stylePreset: stylePreset || undefined,
        metadata: { source: 'images-module' },
      });
      const nextResults = await resolveResultItems(result);
      setResults((prev) => [...nextResults, ...prev]);
      setStatus('success');
    } catch (err: any) {
      setStatus('idle');
      setError(err?.message || t('common.error', 'Something went wrong.'));
    } finally {
      setSubmitting(false);
    }
  };

  const handleAddToCanvas = async (url?: string | null) => {
    const finalUrl = url || results?.[0]?.url || null;
    if (!finalUrl || !engine) return;
    try {
      await engine.objects.addImage({ url: finalUrl, center: true, metadata: { sourceModule: 'ai-text-to-image' } } as any);
    } catch (err: any) {
      setError(err?.message || t('image.aiAddFailed', 'The generated image could not be added to the canvas.'));
    }
  };

  const handleRemoveResult = (id: string) => {
    setResults((prev) => prev.filter((item) => item.id !== id));
  };

  return (
    <Card>
<CardContent className="ask-flex ask-flex-col ask-gap-4">
        <div className="ask-rounded-2xl ask-border ask-border-borderSubtle ask-bg-surfaceAlt ask-p-4">
          <div className="ask-text-[12px] ask-font-semibold ask-text-text">
            {t('image.aiCreateTitle', 'Create an image')}
          </div>
          <div className="ask-mt-1 ask-text-[11px] ask-leading-5 ask-text-textMuted">
            {t('image.aiCreateHint', 'Describe what you want to generate. When the image is ready, add it to your canvas.')}
          </div>
        </div>

        <label className="ask-flex ask-flex-col ask-gap-2 ask-text-[12px]">
          <span className="ask-font-medium ask-text-text">{t('image.aiPrompt', 'Description')} <span className="ask-text-red-500" aria-hidden="true">*</span></span>
          <textarea
            required
            aria-required="true"
            className="ask-theme-input ask-min-h-[124px] ask-rounded-2xl ask-border ask-px-3 ask-py-3 ask-text-[12px] ask-leading-5"
            value={prompt}
            disabled={submitting}
            onInput={(e: any) => setPrompt(String(e.currentTarget.value ?? ''))}
            placeholder={t('image.aiPromptPlaceholder', 'Example: A clean mockup of a white t-shirt floating on a soft neutral background')}
          />
        </label>

        <div className="ask-grid ask-grid-cols-2 ask-gap-3">
          <label className="ask-flex ask-flex-col ask-gap-1 ask-text-[12px]">
            <span className="ask-font-medium ask-text-text">{t('image.aiAspectRatio', 'Format')} <span className="ask-text-red-500" aria-hidden="true">*</span></span>
            <select className="ask-theme-select ask-rounded-xl ask-border ask-px-3 ask-py-2 ask-text-[12px]" required aria-required="true" value={aspectRatio} disabled={submitting} onChange={(e: any) => setAspectRatio(String(e.currentTarget.value || '1:1'))}>
              {RATIO_OPTIONS.map((ratio) => <option key={ratio} value={ratio}>{ratio}</option>)}
            </select>
          </label>
          <label className="ask-flex ask-flex-col ask-gap-1 ask-text-[12px]">
            <span className="ask-font-medium ask-text-text">{t('image.aiStylePreset', 'Style')}</span>
            <select className="ask-theme-select ask-rounded-xl ask-border ask-px-3 ask-py-2 ask-text-[12px]" value={stylePreset} disabled={submitting} onChange={(e: any) => setStylePreset(String(e.currentTarget.value || ''))}>
              {STYLE_OPTIONS.map((item) => <option key={item.value || 'default'} value={item.value}>{t((item as any).labelKey, item.label)}</option>)}
            </select>
          </label>
        </div>

        <label className="ask-flex ask-flex-col ask-gap-2 ask-text-[12px]">
          <span className="ask-font-medium ask-text-text">{t('image.aiNegativePrompt', 'Avoid')}</span>
          <textarea
            className="ask-theme-input ask-min-h-[58px] ask-rounded-2xl ask-border ask-px-3 ask-py-2 ask-text-[12px] ask-leading-5"
            value={negativePrompt}
            disabled={submitting}
            onInput={(e: any) => setNegativePrompt(String(e.currentTarget.value ?? ''))}
            placeholder={t('image.aiNegativePromptPlaceholder', 'Optional: blurry, low quality, cropped')}
          />
        </label>

        {status === 'loading' ? (
          <div className="ask-flex ask-items-center ask-gap-2 ask-module-section ask-text-[12px] ask-text-textMuted">
            <AiSpinner />
            <span>{t('image.aiGeneratingStatus', 'Generating image…')}</span>
          </div>
        ) : status === 'success' ? (
          <div className="ask-rounded-2xl ask-border ask-border-success/20 ask-bg-success/5 ask-p-3 ask-text-[12px] ask-text-text">
            {t('image.aiGeneratedStatus', 'Image ready. Choose one below.')}
          </div>
        ) : null}

        {error ? (
          <div className="ask-rounded-2xl ask-border ask-border-danger/20 ask-bg-danger/5 ask-p-3 ask-text-[12px] ask-text-danger">{error}</div>
        ) : null}

        <div className="ask-flex ask-flex-wrap ask-gap-2">
          <Button onClick={handleGenerate} disabled={submitting || !((permissions as any)?.canAddImage ?? true)}>
            {submitting ? (
              <>
                <AiSpinner />
                {t('image.aiGenerating', 'Generating…')}
              </>
            ) : t('image.aiGenerate', 'Generate')}
          </Button>
        </div>

        {results.length ? (
          <div className="ask-grid ask-grid-cols-2 ask-gap-3">
            {results.map((item) => (
              <div key={item.id} className="ask-overflow-hidden ask-rounded-[16px] ask-border ask-border-borderSubtle ask-bg-surfaceAlt">
                <div className="ask-relative">
                  <img src={item.url} alt={t('image.aiResultAlt', 'Generated image')} className="ask-aspect-square ask-w-full ask-object-cover" loading="lazy" decoding="async" draggable={false} />
                  <button
                    type="button"
                    className="ask-absolute ask-right-2 ask-top-2 ask-inline-flex ask-h-7 ask-w-7 ask-items-center ask-justify-center ask-rounded-full ask-border ask-border-borderSubtle ask-bg-surface/90 ask-text-[13px] ask-font-bold ask-text-text"
                    onClick={() => handleRemoveResult(item.id)}
                    title={t('common.remove', 'Remove')}
                    aria-label={t('common.remove', 'Remove')}
                  >
                    ×
                  </button>
                </div>
                <div className="ask-p-3">
                  <Button variant="secondary" size="sm" className="ask-w-full" onClick={() => void handleAddToCanvas(item.url)} disabled={!((permissions as any)?.canAddImage ?? true)}>
                    {t('common.add', 'Add')}
                  </Button>
                </div>
              </div>
            ))}
          </div>
        ) : null}
      </CardContent>
    </Card>
  );
};

registerModule({
  id: 'image-ai-text-to-image',
  label: getI18n().t('image.aiModuleLabel', 'AI image'),
  icon: 'ai-image',
  displayMode: 'floating',
  keepMounted: true,
  licenseFeature: 'aiCredits',
  supportedEngines: ['fabric', '3d'],
  requiredCapabilities: ['addImage'],
  render: AiTextToImagePanel,
  requiresView: false,
});

export default AiTextToImagePanel;
