import {
  ArrowLeft,
  Loader2,
  Plus,
  Send,
  X,
} from 'lucide-react';
import { useMemo, useState } from 'react';

import type {
  WoodenFishAudioAsset,
  WoodenFishSessionResponse,
  WoodenFishWorkspaceCreateRequest,
} from '../../../../packages/shared/src/contracts/woodenFish';
import { readPuzzleReferenceImageAsDataUrl } from '../../../services/puzzleReferenceImage';
import { uploadWoodenFishHitSoundAsset } from '../../../services/wooden-fish/woodenFishAssetClient';
import { woodenFishClient } from '../../../services/wooden-fish/woodenFishClient';
import {
  WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT,
  WOODEN_FISH_DEFAULT_HIT_SOUND_ASSET,
} from '../../../services/wooden-fish/woodenFishDefaults';
import { CreativeAudioInputPanel } from '../../common/CreativeAudioInputPanel';
import {
  type PendingCreativeAudioAsset,
  prepareCreativeAudioFileForLocalUse,
} from '../../common/creativeAudioProcessing';
import { CreativeImageInputPanel } from '../../common/CreativeImageInputPanel';

type WoodenFishCreationWorkspaceProps = {
  isBusy?: boolean;
  error?: string | null;
  onBack: () => void;
  onSubmitted: (
    result: WoodenFishSessionResponse,
    payload: WoodenFishWorkspaceCreateRequest,
  ) => void;
  showBackButton?: boolean;
  unifiedChrome?: boolean;
};

type WoodenFishWorkspaceFormState = {
  hitObjectPrompt: string;
  hitObjectReferenceImageSrc: string;
  hitSoundAsset: PendingCreativeAudioAsset | null;
  floatingWords: string[];
};

const DEFAULT_THEME_TAGS = ['敲木鱼', '解压'];
const DEFAULT_FLOATING_WORDS = ['幸运'];
const MAX_FLOATING_WORD_COUNT = 8;

const DEFAULT_FORM_STATE: WoodenFishWorkspaceFormState = {
  hitObjectPrompt: '',
  hitObjectReferenceImageSrc: '',
  hitSoundAsset: null,
  floatingWords: DEFAULT_FLOATING_WORDS,
};

function normalizeFloatingWords(words: string[]) {
  const seen = new Set<string>();
  const normalized: string[] = [];
  for (const word of words) {
    const trimmed = word.trim().replace(/[+＋]\s*1$/u, '').trim();
    if (!trimmed || seen.has(trimmed)) {
      continue;
    }
    seen.add(trimmed);
    normalized.push(trimmed);
    if (normalized.length >= 8) {
      break;
    }
  }
  return normalized.length > 0 ? normalized : [...DEFAULT_FLOATING_WORDS];
}

export function WoodenFishCreationWorkspace({
  isBusy = false,
  error = null,
  onBack,
  onSubmitted,
  showBackButton = true,
  unifiedChrome = false,
}: WoodenFishCreationWorkspaceProps) {
  const [formState, setFormState] = useState(DEFAULT_FORM_STATE);
  const [localError, setLocalError] = useState<string | null>(null);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [aiRedraw, setAiRedraw] = useState(true);

  const normalizedFloatingWords = useMemo(
    () => normalizeFloatingWords(formState.floatingWords),
    [formState.floatingWords],
  );
  const canSubmit = normalizedFloatingWords.length > 0;

  const updateFloatingWord = (index: number, value: string) => {
    setFormState((current) => {
      const nextWords = [...current.floatingWords];
      nextWords[index] = value;
      return {
        ...current,
        floatingWords: nextWords.slice(0, MAX_FLOATING_WORD_COUNT),
      };
    });
  };

  const addFloatingWord = () => {
    setFormState((current) => {
      if (current.floatingWords.length >= MAX_FLOATING_WORD_COUNT) {
        return current;
      }
      return {
        ...current,
        floatingWords: [...current.floatingWords, ''],
      };
    });
  };

  const removeFloatingWord = (index: number) => {
    if (index <= 0) {
      return;
    }
    setFormState((current) => ({
      ...current,
      floatingWords: current.floatingWords.filter(
        (_word, currentIndex) => currentIndex !== index,
      ),
    }));
  };

  const handleSubmit = async () => {
    if (!canSubmit || isSubmitting || isBusy) {
      setLocalError('请先补全输入。');
      return;
    }

    setIsSubmitting(true);
    setLocalError(null);

    try {
      const hitSoundAsset: WoodenFishAudioAsset = formState.hitSoundAsset
        ? await uploadWoodenFishHitSoundAsset(
            new File([formState.hitSoundAsset.blob], formState.hitSoundAsset.fileName, {
              type: formState.hitSoundAsset.mimeType,
            }),
            formState.hitSoundAsset.source,
          )
        : WOODEN_FISH_DEFAULT_HIT_SOUND_ASSET;
      const payload: WoodenFishWorkspaceCreateRequest = {
        templateId: 'wooden-fish',
        workTitle: '',
        workDescription:
          formState.hitObjectPrompt.trim() || WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT,
        themeTags: DEFAULT_THEME_TAGS,
        hitObjectPrompt:
          formState.hitObjectPrompt.trim() || WOODEN_FISH_DEFAULT_HIT_OBJECT_PROMPT,
        hitObjectReferenceImageSrc:
          formState.hitObjectReferenceImageSrc.trim() || null,
        hitSoundPrompt: null,
        hitSoundAsset,
        floatingWords: normalizedFloatingWords,
      };
      const response = await woodenFishClient.createSession(payload);
      onSubmitted(response, payload);
    } catch (caughtError) {
      setLocalError(
        caughtError instanceof Error ? caughtError.message : '创建草稿失败。',
      );
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <div
      className={
        unifiedChrome
          ? 'wooden-fish-workspace mx-auto flex min-h-0 w-full max-w-none flex-col overflow-visible'
          : 'wooden-fish-workspace platform-remap-surface mx-auto flex w-full max-w-5xl flex-col px-3 pb-3 pt-3 sm:px-4 sm:pt-4'
      }
      data-unified-chrome={unifiedChrome ? 'true' : 'false'}
    >
      {showBackButton ? (
        <div className="mb-3 flex items-center justify-between gap-3">
          <button
            type="button"
            onClick={onBack}
            className="platform-button platform-button--ghost min-h-0 px-3 py-2 text-sm"
          >
            <ArrowLeft className="h-4 w-4" />
            返回
          </button>
        </div>
      ) : null}

      <div className="grid gap-3 lg:grid-cols-[minmax(0,1.12fr)_minmax(19rem,0.88fr)]">
        <div className="flex min-h-[26rem] min-w-0 flex-col">
          <CreativeImageInputPanel
            fillHeight={!unifiedChrome}
            disabled={isBusy || isSubmitting}
            isSubmitting={isSubmitting}
            uploadedImageSrc={formState.hitObjectReferenceImageSrc}
            uploadedImageAlt="敲击物参考图"
            mainImageInputId="wooden-fish-hit-object-reference"
            promptTextareaId="wooden-fish-hit-object-prompt"
            prompt={formState.hitObjectPrompt}
            promptLabel="敲什么"
            promptRows={4}
            aiRedraw={aiRedraw}
            promptReferenceImages={[]}
            showSubmitButton={false}
            submitLabel="生成"
            submitDisabled={!canSubmit || isSubmitting || isBusy}
            labels={{
              imageField: '参考图',
              uploadImage: '上传参考图',
              replaceImage: '替换参考图',
              emptyImageHint: '上传图像',
              removeImage: '移除参考图',
              removeImageConfirmTitle: '移除参考图',
              removeImageConfirmBody: '移除后仍可用文字描述生成敲击物图案。',
              promptReferenceUpload: '上传参考图',
              promptReferencePreviewAlt: '敲击物参考图',
              closePromptReferencePreview: '关闭预览',
            }}
            onMainImageFileSelect={(file) => {
              void readPuzzleReferenceImageAsDataUrl(file)
                .then((dataUrl) => {
                  setLocalError(null);
                  setFormState((current) => ({
                    ...current,
                    hitObjectReferenceImageSrc: dataUrl,
                  }));
                  setAiRedraw(true);
                })
                .catch((caughtError) => {
                  setLocalError(
                    caughtError instanceof Error
                      ? caughtError.message
                      : '参考图读取失败。',
                  );
                });
            }}
            onMainImageRemove={() => {
              setFormState((current) => ({
                ...current,
                hitObjectReferenceImageSrc: '',
              }));
            }}
            onAiRedrawChange={setAiRedraw}
            onPromptChange={(value) =>
              setFormState((current) => ({
                ...current,
                hitObjectPrompt: value,
              }))
            }
            onSubmit={handleSubmit}
          />
        </div>

        <div className="flex flex-col gap-3 pr-0 lg:pr-1">
          <CreativeAudioInputPanel<PendingCreativeAudioAsset>
            disabled={isBusy || isSubmitting}
            title="敲击音效"
            defaultLabel="默认木鱼音"
            limitLabel="最长 1 秒"
            asset={formState.hitSoundAsset}
            buildRecordedFileName={() => `wooden-fish-hit-${Date.now()}.webm`}
            readFileAsAsset={prepareCreativeAudioFileForLocalUse}
            onAssetChange={(asset) => {
              if (
                formState.hitSoundAsset?.previewUrl &&
                formState.hitSoundAsset.previewUrl !== asset?.previewUrl &&
                typeof URL !== 'undefined' &&
                typeof URL.revokeObjectURL === 'function'
              ) {
                URL.revokeObjectURL(formState.hitSoundAsset.previewUrl);
              }
              setFormState((current) => ({
                ...current,
                hitSoundAsset: asset,
              }));
            }}
            onError={setLocalError}
          />

          <section className="platform-subpanel rounded-[1.25rem] p-4">
            <div className="mb-3 text-sm font-black text-[var(--platform-text-strong)]">
              功德有什么
            </div>
            <div className="grid gap-2 sm:grid-cols-2">
              {formState.floatingWords.map((word, index) => (
                <div key={index} className="relative">
                  <input
                    value={word}
                    maxLength={16}
                    disabled={isBusy || isSubmitting}
                    aria-label={`功德词条 ${index + 1}`}
                    onChange={(event) =>
                      updateFloatingWord(index, event.target.value)
                    }
                    className="h-12 w-full rounded-[0.95rem] border border-[var(--platform-subpanel-border)] bg-white/90 px-3 pr-10 text-sm font-semibold text-[var(--platform-text-strong)] outline-none"
                  />
                  {index > 0 ? (
                    <button
                      type="button"
                      disabled={isBusy || isSubmitting}
                      onClick={() => removeFloatingWord(index)}
                      className="absolute right-2 top-1/2 inline-flex h-7 w-7 -translate-y-1/2 items-center justify-center rounded-full bg-white/92 text-[var(--platform-text-soft)] shadow-sm transition hover:text-[var(--platform-accent)] disabled:opacity-45"
                      aria-label={`删除功德词条 ${index + 1}`}
                      title="删除词条"
                    >
                      <X className="h-3.5 w-3.5" />
                    </button>
                  ) : null}
                </div>
              ))}
              {formState.floatingWords.length < MAX_FLOATING_WORD_COUNT ? (
                <button
                  type="button"
                  disabled={isBusy || isSubmitting}
                  onClick={addFloatingWord}
                  className="grid h-12 place-items-center rounded-[0.95rem] border border-dashed border-[var(--platform-subpanel-border)] bg-white/55 text-[var(--platform-text-soft)] transition hover:border-[var(--platform-accent)] hover:bg-white/78 hover:text-[var(--platform-accent)] disabled:opacity-45"
                  aria-label="新增功德词条"
                  title="新增词条"
                >
                  <Plus className="h-5 w-5" />
                </button>
              ) : null}
            </div>
          </section>
        </div>
      </div>

      {localError || error ? (
        <div className="platform-banner platform-banner--danger mt-3 rounded-2xl text-sm leading-6">
          {localError ?? error}
        </div>
      ) : null}

      <div className="mt-3 flex justify-end gap-2 pb-[max(0.25rem,env(safe-area-inset-bottom))]">
        <button
          type="button"
          onClick={handleSubmit}
          disabled={!canSubmit || isSubmitting || isBusy}
          className={`platform-button platform-button--primary min-h-11 justify-center gap-2 px-5 py-3 ${!canSubmit || isSubmitting || isBusy ? 'cursor-not-allowed opacity-55' : ''}`}
        >
          {isSubmitting ? (
            <Loader2 className="h-4 w-4 animate-spin" />
          ) : (
            <Send className="h-4 w-4" />
          )}
          生成
        </button>
      </div>
    </div>
  );
}

export default WoodenFishCreationWorkspace;
