// ---------------------------------------------------------------------------
// SecondaryFileViewer — read-only viewer for non-SKILL.md files
// ---------------------------------------------------------------------------

import { useState, useCallback, useEffect } from "react";
import type { SkillFileContent } from "../types";
import { renderMarkdown } from "../utils/renderMarkdown";
import { api } from "../api";

type ViewMode = "raw" | "split" | "preview";

function formatBytes(bytes: number): string {
  if (bytes < 1024) return `${bytes} B`;
  if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
  return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
}

function formatJson(raw: string): string {
  try {
    return JSON.stringify(JSON.parse(raw), null, 2);
  } catch {
    return raw;
  }
}

function getFileType(path: string): "json" | "md" | "other" {
  const lower = path.toLowerCase();
  if (lower.endsWith(".json")) return "json";
  if (lower.endsWith(".md")) return "md";
  return "other";
}

interface RawPaneProps {
  content: string;
}

function RawPane({ content }: RawPaneProps) {
  return (
    <textarea
      readOnly
      value={content}
      style={{
        flex: 1,
        width: "100%",
        resize: "none",
        background: "var(--surface-1)",
        color: "var(--text-primary)",
        border: "none",
        outline: "none",
        padding: "12px 16px",
        fontSize: 12,
        fontFamily: "var(--font-mono, monospace)",
        lineHeight: 1.6,
      }}
    />
  );
}

interface PreviewPaneProps {
  content: string;
  fileType: "json" | "md" | "other";
}

function PreviewPane({ content, fileType }: PreviewPaneProps) {
  if (fileType === "json") {
    const formatted = formatJson(content);
    return (
      <pre
        style={{
          flex: 1,
          margin: 0,
          padding: "12px 16px",
          overflow: "auto",
          background: "var(--surface-0)",
          color: "var(--text-primary)",
          fontSize: 12,
          fontFamily: "var(--font-mono, monospace)",
          lineHeight: 1.6,
          whiteSpace: "pre-wrap",
          wordBreak: "break-word",
        }}
      >
        {formatted}
      </pre>
    );
  }

  if (fileType === "md") {
    return (
      <div
        style={{
          flex: 1,
          overflow: "auto",
          padding: "16px 20px",
          background: "var(--surface-0)",
          color: "var(--text-primary)",
          fontSize: 13,
          lineHeight: 1.6,
        }}
        dangerouslySetInnerHTML={{ __html: renderMarkdown(content) }}
      />
    );
  }

  return (
    <pre
      style={{
        flex: 1,
        margin: 0,
        padding: "12px 16px",
        overflow: "auto",
        background: "var(--surface-0)",
        color: "var(--text-primary)",
        fontSize: 12,
        fontFamily: "var(--font-mono, monospace)",
        lineHeight: 1.6,
        whiteSpace: "pre-wrap",
        wordBreak: "break-word",
      }}
    >
      {content}
    </pre>
  );
}

function highlightJson(raw: string): string {
  try {
    const formatted = JSON.stringify(JSON.parse(raw), null, 2);
    return formatted
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"([^"\\]|\\.)*"\s*:/g, (m) => `<span style="color:#6383ff">${m}</span>`)
      .replace(/:\s*"([^"\\]|\\.)*"/g, (m) => `<span style="color:#22c55e">${m.slice(0, 2)}<span style="color:#22c55e">${m.slice(2)}</span></span>`)
      .replace(/:\s*(-?\d+\.?\d*)/g, (m, n) => `: <span style="color:#fb923c">${n}</span>`)
      .replace(/:\s*(true|false|null)/g, (m, kw) => `: <span style="color:#a855f7">${kw}</span>`);
  } catch {
    return raw.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
  }
}

interface SecondaryFileViewerProps {
  file: SkillFileContent | null;
  loading: boolean;
  error: string | null;
  viewMode: ViewMode;
  plugin?: string;
  skill?: string;
  onSaved?: () => void;
  onDirtyChange?: (dirty: boolean) => void;
}

export function SecondaryFileViewer({ file, loading, error, viewMode, plugin, skill, onSaved, onDirtyChange }: SecondaryFileViewerProps) {
  const [localViewMode, setLocalViewMode] = useState<ViewMode>(viewMode);
  const [editing, setEditing] = useState(false);
  const [editContent, setEditContent] = useState("");
  const [saving, setSaving] = useState(false);
  const [toast, setToast] = useState<string | null>(null);

  // Sync prop changes (e.g. user toggles in EditorPanel toolbar)
  const effectiveMode = viewMode !== localViewMode ? viewMode : localViewMode;

  // Notify parent of dirty state
  useEffect(() => {
    onDirtyChange?.(editing);
  }, [editing, onDirtyChange]);

  const handleEdit = useCallback(() => {
    if (file?.content != null) {
      setEditContent(file.content);
      setEditing(true);
    }
  }, [file]);

  const handleCancel = useCallback(() => {
    setEditing(false);
  }, []);

  const handleSave = useCallback(async () => {
    if (!plugin || !skill || !file) return;
    setSaving(true);
    try {
      await api.saveSkillFile(plugin, skill, file.path, editContent);
      setToast("Saved");
      setEditing(false);
      onSaved?.();
      setTimeout(() => setToast(null), 2000);
    } catch (err) {
      setToast(`Save failed: ${(err as Error).message}`);
      setTimeout(() => setToast(null), 3000);
    } finally {
      setSaving(false);
    }
  }, [plugin, skill, file, editContent, onSaved]);

  // Ctrl+S / Cmd+S keyboard shortcut
  useEffect(() => {
    if (!editing) return;
    const handler = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "s") {
        e.preventDefault();
        handleSave();
      }
    };
    document.addEventListener("keydown", handler);
    return () => document.removeEventListener("keydown", handler);
  }, [editing, handleSave]);

  if (loading) {
    return (
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-tertiary)", fontSize: 13 }}>
        Loading…
      </div>
    );
  }

  if (error) {
    return (
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", padding: 24 }}>
        <div
          style={{
            background: "var(--surface-2)",
            border: "1px solid var(--border-subtle)",
            borderRadius: 8,
            padding: "16px 20px",
            maxWidth: 400,
            textAlign: "center",
          }}
        >
          <div style={{ fontSize: 13, color: "var(--text-primary)", fontWeight: 600, marginBottom: 6 }}>Unable to open file</div>
          <div style={{ fontSize: 12, color: "var(--text-tertiary)" }}>{error}</div>
        </div>
      </div>
    );
  }

  if (!file) {
    return null;
  }

  if (file.binary) {
    return (
      <div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "var(--text-tertiary)", fontSize: 13 }}>
        Binary file ({formatBytes(file.size)}) — cannot be displayed
      </div>
    );
  }

  const content = file.content ?? "";
  const fileType = getFileType(file.path);

  return (
    <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
      {/* Truncation warning */}
      {file.truncated && (
        <div
          style={{
            padding: "4px 12px",
            background: "var(--warning-muted, #fef3c7)",
            borderBottom: "1px solid var(--border-subtle)",
            fontSize: 11,
            color: "var(--warning-text, #92400e)",
          }}
        >
          File truncated at {formatBytes(512 * 1024)} — {formatBytes(file.size)} total
        </div>
      )}

      {/* Toolbar — always visible for non-binary files */}
      <div
        style={{
          display: "flex",
          gap: 4,
          padding: "4px 8px",
          borderBottom: "1px solid var(--border-subtle)",
          background: "var(--surface-0)",
        }}
      >
        {/* View mode toggles — only for md/json */}
        {(fileType === "md" || fileType === "json") && (["raw", "split", "preview"] as ViewMode[]).map((mode) => (
          <button
            key={mode}
            onClick={() => setLocalViewMode(mode)}
            style={{
              padding: "2px 8px",
              fontSize: 11,
              background: effectiveMode === mode ? "var(--accent-muted)" : "none",
              color: effectiveMode === mode ? "var(--accent)" : "var(--text-tertiary)",
              border: "none",
              borderRadius: 3,
              cursor: "pointer",
              textTransform: "capitalize",
            }}
          >
            {mode}
          </button>
        ))}
        <span
          style={{
            marginLeft: "auto",
            fontSize: 11,
            color: "var(--text-tertiary)",
            display: "flex",
            alignItems: "center",
            gap: 6,
          }}
        >
          {formatBytes(file.size)}
          {plugin && skill && !file.binary && !editing && (
            <button
              onClick={handleEdit}
              style={{
                padding: "1px 6px",
                fontSize: 10,
                background: "var(--accent-muted)",
                color: "var(--accent)",
                border: "none",
                borderRadius: 3,
                cursor: "pointer",
              }}
            >
              Edit
            </button>
          )}
          {editing && (
            <>
              <button
                onClick={handleSave}
                disabled={saving}
                style={{
                  padding: "1px 6px",
                  fontSize: 10,
                  background: "var(--accent)",
                  color: "#fff",
                  border: "none",
                  borderRadius: 3,
                  cursor: "pointer",
                  opacity: saving ? 0.6 : 1,
                }}
              >
                {saving ? "Saving..." : "Save"}
              </button>
              <button
                onClick={handleCancel}
                style={{
                  padding: "1px 6px",
                  fontSize: 10,
                  background: "var(--surface-3)",
                  color: "var(--text-tertiary)",
                  border: "none",
                  borderRadius: 3,
                  cursor: "pointer",
                }}
              >
                Cancel
              </button>
            </>
          )}
        </span>
      </div>

      {/* Toast */}
      {toast && (
        <div
          style={{
            padding: "4px 12px",
            background: toast.startsWith("Save failed") ? "var(--red-muted)" : "var(--green-muted)",
            borderBottom: "1px solid var(--border-subtle)",
            fontSize: 11,
            color: toast.startsWith("Save failed") ? "var(--red)" : "var(--green)",
          }}
        >
          {toast}
        </div>
      )}

      {/* Content area */}
      <div style={{ flex: 1, display: "flex", flexDirection: "column", minHeight: 0 }}>
        {editing ? (
          <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "auto" }}>
            <textarea
              value={editContent}
              onChange={(e) => setEditContent(e.target.value)}
              style={{
                flex: 1,
                width: "100%",
                resize: "none",
                background: "var(--surface-0)",
                color: "var(--text-primary)",
                border: "none",
                outline: "none",
                padding: "12px 16px",
                fontSize: 12,
                fontFamily: "var(--font-mono, monospace)",
                lineHeight: 1.6,
              }}
            />
            {/* Sticky save bar */}
            <div
              style={{
                position: "sticky",
                bottom: 0,
                display: "flex",
                alignItems: "center",
                gap: 8,
                padding: "6px 12px",
                background: "var(--surface-1)",
                borderTop: "1px solid var(--border-subtle)",
              }}
            >
              <span style={{ flex: 1, fontSize: 11, color: "var(--text-tertiary)" }}>
                Unsaved changes
              </span>
              <button
                onClick={handleSave}
                disabled={saving}
                style={{
                  padding: "3px 12px",
                  fontSize: 11,
                  background: "var(--accent)",
                  color: "#fff",
                  border: "none",
                  borderRadius: 4,
                  cursor: "pointer",
                  opacity: saving ? 0.6 : 1,
                }}
              >
                {saving ? "Saving..." : "Save"}
              </button>
              <button
                onClick={handleCancel}
                style={{
                  padding: "3px 12px",
                  fontSize: 11,
                  background: "var(--surface-3)",
                  color: "var(--text-tertiary)",
                  border: "none",
                  borderRadius: 4,
                  cursor: "pointer",
                }}
              >
                Cancel
              </button>
            </div>
          </div>
        ) : effectiveMode === "split" && fileType !== "other" ? (
          <>
            <div style={{ flex: 1, display: "flex", flexDirection: "column", borderRight: "1px solid var(--border-subtle)" }}>
              <RawPane content={content} />
            </div>
            <div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "auto" }}>
              {fileType === "json" ? (
                <pre
                  style={{
                    flex: 1,
                    margin: 0,
                    padding: "12px 16px",
                    overflow: "auto",
                    background: "var(--surface-0)",
                    fontSize: 12,
                    fontFamily: "var(--font-mono, monospace)",
                    lineHeight: 1.6,
                    whiteSpace: "pre-wrap",
                    wordBreak: "break-word",
                  }}
                  dangerouslySetInnerHTML={{ __html: highlightJson(content) }}
                />
              ) : (
                <PreviewPane content={content} fileType={fileType} />
              )}
            </div>
          </>
        ) : effectiveMode === "preview" && fileType !== "other" ? (
          fileType === "json" ? (
            <pre
              style={{
                flex: 1,
                margin: 0,
                padding: "12px 16px",
                overflow: "auto",
                background: "var(--surface-0)",
                fontSize: 12,
                fontFamily: "var(--font-mono, monospace)",
                lineHeight: 1.6,
                whiteSpace: "pre-wrap",
                wordBreak: "break-word",
              }}
              dangerouslySetInnerHTML={{ __html: highlightJson(content) }}
            />
          ) : (
            <PreviewPane content={content} fileType={fileType} />
          )
        ) : (
          <RawPane content={content} />
        )}
      </div>
    </div>
  );
}
