/**
 * Config Editor Component
 *
 * Enhanced UI for viewing and editing Codex and Claude config files.
 * Features:
 * - Collapsible card container
 * - Smart status indicator
 * - Format button for JSON
 * - Auto-resize editor
 */

import { useAtomValue, useSetAtom } from "jotai";
import { ChevronDown, ChevronUp, Sparkles } from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { dispatchCommandAtom } from "../../../atoms/connection";
import { Button, EmptyState, Spinner, ThemedIcon, Tooltip } from "../../../components/ui";
import { useTranslation } from "../../../lib/i18n";
import { MonacoHost } from "../../code-editor/components/monaco-host";
import { pushToastAtom } from "../../notifications/atoms";

export type ConfigType = "codex" | "claude";

interface ConfigEditorProps {
  configType: ConfigType;
  visible?: boolean;
  fillHeight?: boolean;
}

interface ConfigReadResult {
  configPath: string;
  content: string;
  exists: boolean;
}

interface ConfigWriteResult {
  success: boolean;
  backupPath: string | null;
  error?: string;
}

type SaveStatus = "saved" | "dirty" | "saving" | "error";

const configCardLoadingStateStyle = {
  minHeight: "200px",
  padding: 0,
  gap: 0,
};

const configCardLoadingTitleStyle = {
  margin: 0,
  color: "var(--text-tertiary)",
  fontSize: "var(--text-base)",
  fontWeight: "var(--font-normal)",
};

export function ConfigEditor({
  configType,
  visible = true,
  fillHeight = false,
}: ConfigEditorProps) {
  const t = useTranslation();
  const dispatch = useAtomValue(dispatchCommandAtom);
  const pushToast = useSetAtom(pushToastAtom);

  const [content, setContent] = useState("");
  const [originalContent, setOriginalContent] = useState("");
  const [configPath, setConfigPath] = useState("");
  const [fileExists, setFileExists] = useState(true);
  const [isLoading, setIsLoading] = useState(true);
  const [isSaving, setIsSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [isExpanded, setIsExpanded] = useState(() => {
    // Restore from localStorage
    const stored = localStorage.getItem(`config-expanded-${configType}`);
    return stored !== null ? stored === "true" : true;
  });

  // Compute save status
  const saveStatus: SaveStatus = useMemo(() => {
    if (isSaving) return "saving";
    if (error) return "error";
    if (content !== originalContent) return "dirty";
    return "saved";
  }, [isSaving, error, content, originalContent]);

  const isDirty = saveStatus === "dirty";

  // Load config file on mount or when configType changes
  useEffect(() => {
    let cancelled = false;

    const loadConfig = async () => {
      setIsLoading(true);
      setError(null);

      try {
        const result = await dispatch<ConfigReadResult>("settings.readConfigFile", {
          configType,
        });

        if (cancelled) return;

        if (result.ok && result.data) {
          setContent(result.data.content);
          setOriginalContent(result.data.content);
          setConfigPath(result.data.configPath);
          setFileExists(result.data.exists);
        } else {
          setError(result.error?.message ?? t("settings.config_files.load_failed"));
        }
      } catch {
        if (!cancelled) {
          setError(t("settings.config_files.load_failed"));
        }
      } finally {
        if (!cancelled) {
          setIsLoading(false);
        }
      }
    };

    void loadConfig();

    return () => {
      cancelled = true;
    };
  }, [configType, dispatch, t]);

  // Persist expanded state
  useEffect(() => {
    localStorage.setItem(`config-expanded-${configType}`, String(isExpanded));
  }, [isExpanded, configType]);

  const handleSave = useCallback(async () => {
    if (!isDirty || isSaving) return;

    setIsSaving(true);

    try {
      const result = await dispatch<ConfigWriteResult>("settings.writeConfigFile", {
        configType,
        content,
      });

      if (result.ok && result.data?.success) {
        pushToast({
          kind: "success",
          title: t("settings.config_files.save_success"),
          body: result.data.backupPath
            ? t("settings.config_files.save_success_with_backup", {
                configPath,
                backupPath: result.data.backupPath,
              })
            : undefined,
        });
        setFileExists(true);
        setOriginalContent(content);
        setError(null);
      } else {
        const errorMsg = result.error?.message ?? result.data?.error;
        setError(errorMsg ?? t("settings.config_files.save_failed"));
        pushToast({
          kind: "error",
          title: t("settings.config_files.save_failed"),
          body: errorMsg,
        });
      }
    } catch (err) {
      const errorMsg = err instanceof Error ? err.message : t("settings.config_files.save_failed");
      setError(errorMsg);
      pushToast({
        kind: "error",
        title: t("settings.config_files.save_failed"),
      });
    } finally {
      setIsSaving(false);
    }
  }, [configType, content, isDirty, isSaving, dispatch, pushToast, t]);

  const handleRevert = useCallback(() => {
    setContent(originalContent);
    setError(null);
  }, [originalContent]);

  const handleFormat = useCallback(() => {
    if (configType === "claude") {
      try {
        const parsed = JSON.parse(content);
        const formatted = JSON.stringify(parsed, null, 2);
        setContent(formatted);
        pushToast({
          kind: "success",
          title: t("settings.config_files.json_formatted"),
        });
      } catch {
        pushToast({
          kind: "error",
          title: t("settings.config_files.invalid_json"),
          body: t("settings.config_files.invalid_json_format_body"),
        });
      }
    }
    // TOML formatting not implemented
  }, [configType, content, pushToast, t]);

  const handleContentChange = useCallback((newContent: string) => {
    setContent(newContent);
    setError(null);
  }, []);

  const handleToggle = useCallback(() => {
    setIsExpanded((prev) => !prev);
  }, []);

  // Status indicator component
  const StatusIndicator = () => {
    if (!fileExists && !isSaving && !error && !isDirty) {
      return (
        <div className="config-status config-status--warning">
          <ThemedIcon
            aria-hidden="true"
            className="config-status__icon"
            semantic="state.warning"
            size={14}
          />
          <span>{t("settings.config_files.file_not_found_hint")}</span>
        </div>
      );
    }

    const statusConfig = {
      saved: { color: "success", text: t("settings.config_files.status_saved") },
      dirty: { color: "warning", text: t("settings.config_files.unsaved_changes") },
      saving: { color: "info", text: t("settings.config_files.saving") },
      error: { color: "error", text: t("settings.config_files.save_failed") },
    };

    const config = statusConfig[saveStatus];

    return (
      <div className={`config-status config-status--${config.color}`}>
        {saveStatus === "saving" ? (
          <Spinner label={config.text} size="sm" />
        ) : (
          <ThemedIcon
            aria-hidden="true"
            className="config-status__icon"
            semantic={
              saveStatus === "saved"
                ? "state.success"
                : saveStatus === "dirty"
                  ? "state.warning"
                  : saveStatus === "error"
                    ? "state.error"
                    : "state.info"
            }
            size={14}
          />
        )}
        <span>{config.text}</span>
      </div>
    );
  };

  if (isLoading) {
    return (
      <div className="config-card">
        <EmptyState
          className="config-card-loading"
          style={configCardLoadingStateStyle}
          title={<p style={configCardLoadingTitleStyle}>{t("common.loading")}</p>}
        />
      </div>
    );
  }

  // Error state - but still show the card
  if (error && !configPath) {
    return (
      <div className="config-card">
        <div className="config-card-error">
          <span className="config-card-error-message">{error}</span>
        </div>
      </div>
    );
  }

  return (
    <div className={`config-card ${fillHeight ? "config-card--fill-height" : ""}`}>
      {/* Header */}
      <div className="config-card-header" onClick={handleToggle}>
        <div className="config-card-title">
          <ThemedIcon semantic="state.configFile" size={16} />
          <Tooltip content={configPath}>
            <span className="config-card-path">{configPath}</span>
          </Tooltip>
        </div>
        <div className="config-card-header-right">
          {isExpanded ? <ChevronUp size={16} /> : <ChevronDown size={16} />}
        </div>
      </div>

      {/* Body */}
      {isExpanded && (
        <div className={`config-card-body ${fillHeight ? "config-card-body--fill-height" : ""}`}>
          {!fileExists && (
            <EmptyState
              className="config-empty-state"
              description={
                <div className="config-empty-desc">
                  {t("settings.config_files.file_not_found_hint")}
                </div>
              }
              icon={
                <ThemedIcon className="config-empty-icon" semantic="state.emptyConfig" size={16} />
              }
              title={
                <div className="config-empty-title">
                  {t("settings.config_files.file_not_found")}
                </div>
              }
            />
          )}

          <MonacoHost
            filePath={configPath}
            content={content}
            onContentChange={handleContentChange}
            standalone
            visible={visible}
          />

          {/* Actions */}
          <div className="config-card-actions">
            <div className="config-actions-left">
              <StatusIndicator />
            </div>

            <div className="config-actions-right">
              {configType === "claude" && (
                <Tooltip content={t("settings.config_files.format_hint")}>
                  <Button size="sm" onClick={handleFormat}>
                    <Sparkles size={14} />
                    <span>{t("settings.config_files.format")}</span>
                  </Button>
                </Tooltip>
              )}
              <Button size="sm" onClick={handleRevert} disabled={!isDirty || isSaving}>
                {t("action.reset")}
              </Button>
              <Button
                variant="primary"
                size="sm"
                onClick={handleSave}
                disabled={!isDirty || isSaving}
              >
                {isSaving ? t("settings.config_files.saving") : t("action.save")}
              </Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}
