/**
 * @license
 * SPDX-License-Identifier: Apache-2.0
 */

import React, { useState, useEffect, useMemo } from 'react';
import { motion, AnimatePresence } from 'motion/react';
import Header from './components/Header';
import RuleManagement from './components/RuleManagement';
import SandboxSimulation from './components/SandboxSimulation';
import ToastContainer, { Toast } from './components/ToastContainer';
import {
  ApiError,
  fetchCurrentRules,
  fetchRuleVersions,
  restoreRuleVersion,
  saveAndActivateRules,
} from './api';
import { LlmConfig, Rule, RuleSet, RuleVersionSummary } from './types';

const TRANSFER_SET_ID = 'transfer';
const DEFAULT_LLM_CONFIG: LlmConfig = {
  baseUrl: 'https://api.openai.com/v1',
  model: 'gpt-4.1-mini',
  timeoutMs: 3000,
  maxOutputTokens: 64,
  prompt: '',
};

function emptyTransferSet(): RuleSet {
  return {
    id: TRANSFER_SET_ID,
    name: '潜在转接',
    enabled: true,
    matcher: 'ac-keyword',
    rules: [],
  };
}

function transferRules(ruleSets: RuleSet[]): Rule[] {
  return ruleSets.find(ruleSet => ruleSet.id === TRANSFER_SET_ID)?.rules ?? [];
}

function replaceTransferRules(ruleSets: RuleSet[], rules: Rule[]): RuleSet[] {
  if (!ruleSets.some(ruleSet => ruleSet.id === TRANSFER_SET_ID)) {
    return [{ ...emptyTransferSet(), rules }, ...ruleSets];
  }
  return ruleSets.map(ruleSet =>
    ruleSet.id === TRANSFER_SET_ID ? { ...ruleSet, rules } : ruleSet
  );
}

function transferMatcher(ruleSets: RuleSet[]): 'ac-keyword' | 'llm' {
  return ruleSets.find(ruleSet => ruleSet.id === TRANSFER_SET_ID)?.matcher === 'llm'
    ? 'llm'
    : 'ac-keyword';
}

function replaceTransferMatcher(
  ruleSets: RuleSet[],
  matcher: 'ac-keyword' | 'llm',
): RuleSet[] {
  if (!ruleSets.some(ruleSet => ruleSet.id === TRANSFER_SET_ID)) {
    return [{ ...emptyTransferSet(), matcher }, ...ruleSets];
  }
  return ruleSets.map(ruleSet =>
    ruleSet.id === TRANSFER_SET_ID ? { ...ruleSet, matcher } : ruleSet
  );
}

export default function App() {
  // Global Active Tab: 'rules' | 'sandbox'
  const [activeTab, setActiveTab] = useState<'rules' | 'sandbox'>('rules');

  const [ruleSets, setRuleSets] = useState<RuleSet[]>([]);
  const [publishedRuleSets, setPublishedRuleSets] = useState<RuleSet[]>([]);
  const [llmConfig, setLlmConfig] = useState<LlmConfig>(DEFAULT_LLM_CONFIG);
  const [publishedLlmConfig, setPublishedLlmConfig] = useState<LlmConfig>(DEFAULT_LLM_CONFIG);
  const [publishedVersion, setPublishedVersion] = useState(0);
  const [loadingRules, setLoadingRules] = useState(true);
  const [savingRules, setSavingRules] = useState(false);
  const [versionHistory, setVersionHistory] = useState<RuleVersionSummary[]>([]);
  const [versionHistoryLoading, setVersionHistoryLoading] = useState(false);
  const [restoringVersion, setRestoringVersion] = useState<number | null>(null);

  // Floating notifications
  const [toasts, setToasts] = useState<Toast[]>([]);

  // 1. Toast helper
  const addToast = (message: string, type: 'success' | 'warning' | 'info') => {
    const id = `toast-${Date.now()}-${Math.random().toString(36).substr(2, 5)}`;
    setToasts((prev) => [...prev, { id, message, type }]);

    // Auto remove after 4.5 seconds
    setTimeout(() => {
      removeToast(id);
    }, 4500);
  };

  const removeToast = (id: string) => {
    setToasts((prev) => prev.filter((t) => t.id !== id));
  };

  // Load the active server-side snapshot. The backend is the source of truth.
  useEffect(() => {
    let active = true;
    void fetchCurrentRules()
      .then(data => {
        if (!active) return;
        setRuleSets(data.ruleSets);
        setPublishedRuleSets(data.ruleSets);
        setLlmConfig(data.llmConfig);
        setPublishedLlmConfig(data.llmConfig);
        setPublishedVersion(data.version);
      })
      .catch(error => {
        if (!active) return;
        const message = error instanceof ApiError ? error.message : '无法连接规则服务';
        addToast(`加载规则失败：${message}`, 'warning');
      })
      .finally(() => {
        if (active) setLoadingRules(false);
      });
    return () => {
      active = false;
    };
  }, []);

  const handleUpdateRules = (updatedRules: Rule[]) => {
    setRuleSets(current => replaceTransferRules(current, updatedRules));
  };

  const handleUpdateMatcher = (matcher: 'ac-keyword' | 'llm') => {
    setRuleSets(current => replaceTransferMatcher(current, matcher));
  };

  const isDirty = useMemo(() => {
    return JSON.stringify(ruleSets) !== JSON.stringify(publishedRuleSets)
      || JSON.stringify(llmConfig) !== JSON.stringify(publishedLlmConfig);
  }, [llmConfig, publishedLlmConfig, publishedRuleSets, ruleSets]);

  const handlePublish = async () => {
    if (!isDirty || savingRules || restoringVersion !== null) return;
    setSavingRules(true);
    try {
      const result = await saveAndActivateRules(publishedVersion, llmConfig, ruleSets);
      setRuleSets(result.ruleSets);
      setPublishedRuleSets(result.ruleSets);
      setLlmConfig(result.llmConfig);
      setPublishedLlmConfig(result.llmConfig);
      setPublishedVersion(result.version);
      addToast(`保存成功，监控规则 V${result.version} 已发布生效`, 'success');
      result.warnings.forEach(warning => addToast(warning, 'warning'));
    } catch (error) {
      if (error instanceof ApiError && error.body.code === 'RULE_VERSION_CONFLICT') {
        addToast(`规则版本冲突，服务端当前为 V${error.body.currentVersion ?? '?' }，请刷新页面后重试`, 'warning');
      } else {
        const message = error instanceof ApiError ? error.message : '未知错误';
        addToast(`发布失败：${message}`, 'warning');
      }
    } finally {
      setSavingRules(false);
    }
  };

  const loadVersionHistory = async () => {
    if (versionHistoryLoading) return;
    setVersionHistoryLoading(true);
    try {
      setVersionHistory(await fetchRuleVersions(20));
    } catch (error) {
      const message = error instanceof ApiError ? error.message : '未知错误';
      addToast(`加载历史版本失败：${message}`, 'warning');
    } finally {
      setVersionHistoryLoading(false);
    }
  };

  const handleRestoreVersion = async (sourceVersion: number) => {
    if (restoringVersion !== null || savingRules || sourceVersion === publishedVersion) return;
    const draftWarning = isDirty
      ? '\n当前未发布的页面修改将被回溯结果覆盖。'
      : '';
    const confirmed = window.confirm(
      `确定回溯到 V${sourceVersion}？${draftWarning}\n系统不会删除历史版本，而是基于 V${sourceVersion} 创建并发布一个新版本。`
    );
    if (!confirmed) return;

    setRestoringVersion(sourceVersion);
    try {
      const result = await restoreRuleVersion(sourceVersion, publishedVersion);
      setRuleSets(result.ruleSets);
      setPublishedRuleSets(result.ruleSets);
      setLlmConfig(result.llmConfig);
      setPublishedLlmConfig(result.llmConfig);
      setPublishedVersion(result.version);
      addToast(`已基于 V${sourceVersion} 创建并生效 V${result.version}`, 'success');
      result.warnings.forEach(warning => addToast(warning, 'warning'));
      void loadVersionHistory();
    } catch (error) {
      if (error instanceof ApiError && error.body.code === 'RULE_VERSION_CONFLICT') {
        addToast(`回溯失败：服务端当前已是 V${error.body.currentVersion ?? '?'}，请重新打开版本菜单`, 'warning');
        void loadVersionHistory();
      } else {
        const message = error instanceof ApiError ? error.message : '未知错误';
        addToast(`回溯失败：${message}`, 'warning');
      }
    } finally {
      setRestoringVersion(null);
    }
  };

  const rules = transferRules(ruleSets);
  const activeRules = transferRules(publishedRuleSets);

  return (
    <div className="min-h-screen bg-slate-50 font-sans antialiased flex flex-col selection:bg-blue-100 selection:text-blue-900">
      {/* Dynamic Header */}
      <Header
        activeTab={activeTab}
        setActiveTab={setActiveTab}
        publishedVersion={publishedVersion}
        isDirty={isDirty}
        versionHistory={versionHistory}
        versionHistoryLoading={versionHistoryLoading}
        restoringVersion={restoringVersion}
        onLoadVersionHistory={() => void loadVersionHistory()}
        onRestoreVersion={(version) => void handleRestoreVersion(version)}
      />

      {/* Main Container Area */}
      <main className="flex-1 max-w-7xl w-full mx-auto px-4 py-6 sm:px-6 overflow-hidden">
        <AnimatePresence mode="wait">
          {activeTab === 'rules' ? (
            <motion.div
              key="rules-page"
              initial={{ opacity: 0, y: 15 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -15 }}
              transition={{ duration: 0.18, ease: 'easeOut' }}
              className="h-full"
            >
              <RuleManagement
                rules={rules}
                setRules={handleUpdateRules}
                matcher={transferMatcher(ruleSets)}
                setMatcher={handleUpdateMatcher}
                llmConfig={llmConfig}
                setLlmConfig={setLlmConfig}
                onSavePublish={handlePublish}
                isDirty={isDirty}
                loading={loadingRules}
                saving={savingRules || restoringVersion !== null}
                addToast={addToast}
              />
            </motion.div>
          ) : (
            <motion.div
              key="sandbox-page"
              initial={{ opacity: 0, y: 15 }}
              animate={{ opacity: 1, y: 0 }}
              exit={{ opacity: 0, y: -15 }}
              transition={{ duration: 0.18, ease: 'easeOut' }}
              className="h-full"
            >
              <SandboxSimulation
                rules={activeRules}
                matcher={transferMatcher(publishedRuleSets)}
                addToast={addToast}
              />
            </motion.div>
          )}
        </AnimatePresence>
      </main>

      {/* Persistent Toast Notifications */}
      <ToastContainer toasts={toasts} removeToast={removeToast} />
    </div>
  );
}
