import { useState, useEffect } from 'react';
import { saasClient, type SaaSConfigItem } from '../../lib/saas-client';
import { ArrowLeft, ArrowRight, Upload, Check, Loader2, RefreshCw } from 'lucide-react';

interface LocalModel {
  id: string;
  name: string;
  provider: string;
  [key: string]: unknown;
}

type SyncDirection = 'local-to-saas' | 'saas-to-local' | 'merge';

interface SyncConflict {
  key: string;
  localValue: string | null;
  saasValue: string | null;
}

export function ConfigMigrationWizard({ onDone }: { onDone: () => void }) {
  const [step, setStep] = useState<1 | 2 | 3>(1);
  const [direction, setDirection] = useState<SyncDirection>('local-to-saas');
  const [isSyncing, setIsSyncing] = useState(false);
  const [syncResult, setSyncResult] = useState<'success' | 'partial' | null>(null);
  const [error, setError] = useState<string | null>(null);

  // Data
  const [localModels, setLocalModels] = useState<LocalModel[]>([]);
  const [saasConfigs, setSaasConfigs] = useState<SaaSConfigItem[]>([]);
  const [conflicts, setConflicts] = useState<SyncConflict[]>([]);
  const [selectedKeys, setSelectedKeys] = useState<Set<string>>(new Set());

  // Step 1: Load data
  useEffect(() => {
    if (step !== 1) return;

    // Load local models from localStorage
    try {
      const raw = localStorage.getItem('zclaw-custom-models');
      if (raw) {
        const parsed = JSON.parse(raw) as LocalModel[];
        setLocalModels(Array.isArray(parsed) ? parsed : []);
      }
    } catch {
      setLocalModels([]);
    }

    // Load SaaS config items
    saasClient.listConfig().then(setSaasConfigs).catch(() => setSaasConfigs([]));
  }, [step]);

  const localCount = localModels.length;
  const saasCount = saasConfigs.length;

  // Step 2: Compute conflicts based on direction
  useEffect(() => {
    if (step !== 2) return;

    const found: SyncConflict[] = [];

    if (direction === 'local-to-saas' || direction === 'merge') {
      // Check which local models already exist in SaaS
      for (const model of localModels) {
        const exists = saasConfigs.some((c) => c.key_path === `models.${model.id}`);
        if (exists) {
          found.push({
            key: model.id,
            localValue: JSON.stringify({ name: model.name, provider: model.provider }),
            saasValue: '已存在',
          });
        }
      }
    }

    if (direction === 'saas-to-local' || direction === 'merge') {
      // SaaS configs that have values not in local
      for (const config of saasConfigs) {
        if (!config.current_value) continue;
        const localRaw = localStorage.getItem('zclaw-custom-models');
        const localModels: LocalModel[] = localRaw ? JSON.parse(localRaw) : [];
        const isLocal = localModels.some((m) => m.id === config.key_path.replace('models.', ''));
        if (!isLocal && config.category === 'model') {
          found.push({
            key: config.key_path,
            localValue: null,
            saasValue: config.current_value,
          });
        }
      }
    }

    setConflicts(found);
    setSelectedKeys(new Set(found.map((c) => c.key)));
  }, [step, direction, localModels, saasConfigs]);

  // Step 3: Execute sync
  async function executeSync() {
    setIsSyncing(true);
    setError(null);

    try {
      if (direction === 'local-to-saas' && localModels.length > 0) {
        // Push local models as config items
        for (const model of localModels) {
          const existingItem = saasConfigs.find((c) => c.key_path === `models.${model.id}`);
          if (existingItem && !selectedKeys.has(model.id)) continue;

          const body = {
            category: 'model',
            key_path: `models.${model.id}`,
            value_type: 'json',
            current_value: JSON.stringify({ name: model.name, provider: model.provider }),
            source: 'desktop',
            description: `从桌面端同步: ${model.name}`,
          };

          if (existingItem) {
            await saasClient.request<unknown>('PUT', `/api/v1/config/items/${existingItem.id}`, body);
          } else {
            await saasClient.request<unknown>('POST', '/api/v1/config/items', body);
          }
        }
      } else if (direction === 'saas-to-local' && saasConfigs.length > 0) {
        // Pull SaaS models to local
        const syncedModels = localModels.filter((m) => !selectedKeys.has(m.id));
        const saasModels = saasConfigs
          .filter((c) => c.category === 'model' && c.current_value)
          .map((c) => {
            try {
              return JSON.parse(c.current_value!) as LocalModel;
            } catch {
              return null;
            }
          })
          .filter((m): m is LocalModel => m !== null);

        const merged = [...syncedModels, ...saasModels];
        localStorage.setItem('zclaw-custom-models', JSON.stringify(merged));
      } else if (direction === 'merge') {
        // Merge: local wins for conflicts
        const kept = localModels.filter((m) => !selectedKeys.has(m.id));
        const saasOnly = saasConfigs
          .filter((c) => c.category === 'model' && c.current_value)
          .map((c) => {
            try {
              return JSON.parse(c.current_value!) as LocalModel;
            } catch {
              return null;
            }
          })
          .filter((m): m is LocalModel => m !== null)
          .filter((m) => !localModels.some((lm) => lm.id === m.id));

        const merged = [...kept, ...saasOnly];
        localStorage.setItem('zclaw-custom-models', JSON.stringify(merged));
      }

      setSyncResult(conflicts.length > 0 && conflicts.length === selectedKeys.size ? 'partial' : 'success');
    } catch (err: unknown) {
      setError(err instanceof Error ? err.message : '同步失败');
    } finally {
      setIsSyncing(false);
    }
  }

  // Reset
  function reset() {
    setStep(1);
    setDirection('local-to-saas');
    setSyncResult(null);
    setError(null);
    setSelectedKeys(new Set());
  }

  return (
    <div className="bg-white rounded-xl border border-gray-200 p-5 shadow-sm">
      {/* Header */}
      <div className="flex items-center justify-between mb-4">
        <div className="flex items-center gap-2">
          <Upload className="w-4 h-4 text-gray-500" />
          <span className="text-sm font-medium text-gray-700">配置迁移向导</span>
        </div>
        {step > 1 && (
          <button onClick={() => setStep((step - 1) as 1 | 2)} className="text-xs text-gray-500 hover:text-gray-700 cursor-pointer">
            <ArrowLeft className="w-3.5 h-3.5 inline" /> 返回
          </button>
        )}
      </div>

      {/* Step 1: Direction & Preview */}
      {step === 1 && (
        <div className="space-y-4">
          <p className="text-sm text-gray-500">
            选择迁移方向，检查本地和 SaaS 平台的配置差异。
          </p>

          <div className="space-y-2">
            <DirectionOption
              label="本地 → SaaS"
              description={`将 ${localCount} 个本地模型推送到 SaaS 平台`}
              selected={direction === 'local-to-saas'}
              onClick={() => setDirection('local-to-saas')}
            />
            <DirectionOption
              label="SaaS → 本地"
              description={`从 SaaS 平台拉取 ${saasCount} 项配置到本地`}
              selected={direction === 'saas-to-local'}
              onClick={() => setDirection('saas-to-local')}
            />
            <DirectionOption
              label="双向合并"
              description="合并两边配置，冲突时保留本地版本"
              selected={direction === 'merge'}
              onClick={() => setDirection('merge')}
            />
          </div>

          <button
            onClick={() => setStep(2)}
            disabled={localCount === 0 && saasCount === 0}
            className="w-full py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg hover:bg-emerald-700 disabled:opacity-50 transition-colors"
          >
            预览变更 <ArrowRight className="w-4 h-4 inline" />
          </button>
        </div>
      )}

      {/* Step 2: Resolve conflicts */}
      {step === 2 && (
        <div className="space-y-4">
          {conflicts.length > 0 ? (
            <>
              <p className="text-sm text-amber-600">
                发现 {conflicts.length} 项冲突。勾选的项目将保留{direction === 'local-to-saas' ? '本地' : 'SaaS'}版本。
              </p>
              <div className="space-y-1.5">
                {conflicts.map((c) => (
                  <label key={c.key} className="flex items-center gap-2 p-2 rounded-lg bg-gray-50 cursor-pointer text-sm">
                    <input
                      type="checkbox"
                      checked={selectedKeys.has(c.key)}
                      onChange={(e) => {
                        setSelectedKeys((prev) => {
                          const next = new Set(prev);
                          if (e.target.checked) next.add(c.key);
                          else next.delete(c.key);
                          return next;
                        });
                      }}
                      className="rounded"
                    />
                    <span className="font-medium text-gray-800">{c.key}</span>
                    <span className="text-xs text-gray-400 truncate">
                      ({direction === 'local-to-saas' ? '本地' : 'SaaS'}: {c.saasValue})
                    </span>
                  </label>
                ))}
              </div>
            </>
          ) : (
            <div className="flex items-center gap-2 text-sm text-emerald-600">
              <Check className="w-4 h-4" />
              <span>无冲突，可直接同步</span>
            </div>
          )}

          <button
            onClick={() => { setStep(3); executeSync(); }}
            className="w-full py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg hover:bg-emerald-700 transition-colors"
          >
            {isSyncing ? (
              <><Loader2 className="w-4 h-4 inline animate-spin" /> 同步中...</>
            ) : (
              <><ArrowRight className="w-4 h-4 inline" /> 执行同步</>
            )}
          </button>
        </div>
      )}

      {/* Step 3: Result */}
      {step === 3 && (
        <div className="space-y-4">
          {syncResult === 'success' ? (
            <div className="flex items-center gap-2 text-sm text-emerald-600">
              <Check className="w-5 h-5" />
              <span>配置同步成功完成</span>
            </div>
          ) : syncResult === 'partial' ? (
            <div className="flex items-center gap-2 text-amber-600">
              <Check className="w-5 h-5" />
              <span>部分同步完成（{conflicts.length} 项跳过）</span>
            </div>
          ) : error ? (
            <div className="text-sm text-red-500">{error}</div>
          ) : null}

          <div className="flex gap-2">
            <button
              onClick={reset}
              className="flex-1 py-2 text-sm text-gray-600 border border-gray-300 rounded-lg hover:bg-gray-50 transition-colors cursor-pointer"
            >
              <RefreshCw className="w-3.5 h-3.5 inline" /> 重新开始
            </button>
            <button
              onClick={onDone}
              className="flex-1 py-2 text-sm font-medium text-white bg-emerald-600 rounded-lg hover:bg-emerald-700 transition-colors"
            >
              完成
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

function DirectionOption({
  label,
  description,
  selected,
  onClick,
}: {
  label: string;
  description: string;
  selected: boolean;
  onClick: () => void;
}) {
  return (
    <button
      onClick={onClick}
      className={`w-full text-left p-3 rounded-lg border transition-colors cursor-pointer ${
        selected ? 'border-emerald-500 bg-emerald-50' : 'border-gray-200 hover:border-gray-300'
      }`}
    >
      <div className="text-sm font-medium text-gray-800">{label}</div>
      <div className="text-xs text-gray-500">{description}</div>
    </button>
  );
}
