import React, { useCallback, useEffect, useState } from "react";
import { useSearchParams } from "react-router-dom";
import { apiClient } from "../api/client";
import { useAuth } from "../state/auth";
import { CodeEditor } from "../components/code-editor";
import { CommitDialog } from "../components/commit-dialog";
import { Icon } from "../components/icon";
import { SyntaxHighlighter } from "../components/syntax-highlighter";
import { detectLanguage } from "../utils/language";

interface FileEditorProps {
  projectId: string;
  repoId: string;
}

export const FileEditor: React.FC<FileEditorProps> = ({
  projectId,
  repoId,
}) => {
  const [searchParams] = useSearchParams();
  const { user } = useAuth();

  const [mode, setMode] = useState<"view" | "edit">("view");
  const [content, setContent] = useState(">");
  const [originalContent, setOriginalContent] = useState(">");
  const [language, setLanguage] = useState("plaintext");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [showCommitDialog, setShowCommitDialog] = useState(false);
  const [isBinary, setIsBinary] = useState(false);
  const [saving, setSaving] = useState(false);

  const branch = searchParams.get("branch") || "main";
  const filePath = searchParams.get("file");

  const loadFile = useCallback(async () => {
    if (!filePath) {
      setContent("");
      setOriginalContent("");
      return;
    }

    setLoading(true);
    setError(null);
    try {
      const response = await apiClient.get(
        `/projects/${projectId}/repositories/${repoId}/files/content`,
        {
          params: {
            branch,
            path: filePath,
          },
        }
      );
      const data = response.data;
      if (data.is_binary) {
        setIsBinary(true);
        setContent("Binary file - cannot display");
        setOriginalContent("");
      } else {
        setIsBinary(false);
        setContent(data.content);
        setOriginalContent(data.content);
        setLanguage(detectLanguage(filePath));
      }
    } catch {
      setError("Failed to load file");
    } finally {
      setLoading(false);
    }
  }, [projectId, repoId, branch, filePath]);

  useEffect(() => {
    void loadFile();
  }, [loadFile]);

  const handleEdit = () => {
    if (isBinary) return;
    setMode("edit");
  };

  const handleCancel = () => {
    setContent(originalContent);
    setMode("view");
    setShowCommitDialog(false);
  };

  const handleSave = () => {
    if (content === originalContent) {
      setMode("view");
      return;
    }
    setShowCommitDialog(true);
  };

  const handleCommit = async (message: string) => {
    if (!filePath || !user) return;

    setSaving(true);
    try {
      await apiClient.post(
        `/projects/${projectId}/repositories/${repoId}/files/content`,
        {
          path: filePath,
          branch,
          content,
          commit_message: message,
          author_name: user.name || "User",
          author_email: user.email || "user@example.com",
        }
      );
      setOriginalContent(content);
      setMode("view");
      setShowCommitDialog(false);
    } catch {
      setError("Failed to save changes");
    } finally {
      setSaving(false);
    }
  };

  // Keyboard shortcuts
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "e") {
        e.preventDefault();
        if (mode === "view" && !isBinary) {
          handleEdit();
        } else if (mode === "edit") {
          handleCancel();
        }
      }
      if ((e.ctrlKey || e.metaKey) && e.key === "s") {
        e.preventDefault();
        if (mode === "edit") {
          handleSave();
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [mode, isBinary, content, originalContent]);

  if (!filePath) {
    return (
      <div className="file-viewer-empty">
        <p className="muted">Select a file to view its contents</p>
      </div>
    );
  }

  if (loading) return <p className="muted">Loading file...</p>;
  if (error) return <p className="error-text">{error}</p>;

  return (
    <div className="file-editor">
      <div className="file-editor-toolbar">
        <div className="file-breadcrumbs">
          {filePath.split("/").map((part, i, arr) => (
            <span key={i}>
              {part}
              {i < arr.length - 1 && (
                <span className="breadcrumb-sep">/</span>
              )}
            </span>
          ))}
        </div>
        <div className="file-actions">
          {mode === "view" && !isBinary && (
            <button
              className="btn-primary"
              onClick={handleEdit}
              type="button"
            >
              <Icon name="edit" size="sm" />
              Edit
            </button>
          )}
          {mode === "edit" && (
            <>
          <button
            className="btn-primary"
            onClick={handleSave}
            disabled={content === originalContent || saving}
            type="button"
          >
            {saving ? (
              <>
                <Icon name="loading" size="sm" />
                Saving...
              </>
            ) : (
              <>
                <Icon name="save" size="sm" />
                Save
              </>
            )}
          </button>
              <button
                className="btn-secondary"
                onClick={handleCancel}
                type="button"
              >
                <Icon name="cancel" size="sm" />
                Cancel
              </button>
            </>
          )}
        </div>
      </div>

      <div className="file-editor-content">
        {mode === "view" && (
          <SyntaxHighlighter
            code={content}
            language={language}
            showLineNumbers={!isBinary}
          />
        )}

        {mode === "edit" && (
          <CodeEditor
            value={content}
            onChange={setContent}
            language={language}
          />
        )}
      </div>

      <CommitDialog
        isOpen={showCommitDialog}
        filePath={filePath}
        originalContent={originalContent}
        newContent={content}
        onCommit={handleCommit}
        onCancel={() => setShowCommitDialog(false)}
      />
    </div>
  );
};
