import { useCallback, useEffect, useState } from "react";
import { Icon } from "../components/icon";

import { Link, useParams, useSearchParams } from "react-router-dom";

import { apiClient } from "../api/client";
import {
  getRepositoryStatus,
  listRepositories,
  type GitRepository,
  type GitStatus,
} from "../api/git_repositories";
import { CommitPanel } from "../components/commit-panel";
import { FileEditor } from "../components/file-editor";
import { GitToolbar } from "../components/git-toolbar";
import { InstanceList } from "../components/instance-list";
import { WorkspaceHeader } from "../components/workspace-header";
import { listToolTypes } from "../api/tool_types";
import type { ToolType } from "../api/tool_types";

type WorkspaceStatus = "loading" | "ready" | "error" | "empty";

interface FileTreeEntry {
  name: string;
  type: "file" | "directory";
  path: string;
  size?: number;
  mode?: string;
  last_commit?: {
    hash: string;
    message: string;
    author: string;
    date: string;
  } | null;
}

interface Project {
  id: string;
  name: string;
  description?: string | null;
}

export const RepoWorkspace = () => {
  const { projectId } = useParams<{ projectId: string }>();
  const [searchParams, setSearchParams] = useSearchParams();

  const [status, setStatus] = useState<WorkspaceStatus>("loading");
  const [project, setProject] = useState<Project | null>(null);
  const [repositories, setRepositories] = useState<GitRepository[]>([]);
  const [selectedRepoId, setSelectedRepoId] = useState<string | null>(
    searchParams.get("repo")
  );
  const [branches, setBranches] = useState<string[]>([]);
  const [currentBranch, setCurrentBranch] = useState<string>("main");
  const [gitStatus, setGitStatus] = useState<GitStatus | null>(null);
  const [toolTypes, setToolTypes] = useState<ToolType[]>([]);

  const loadProject = useCallback(async () => {
    if (!projectId) return;
    try {
      const response = await apiClient.get(`/projects/${projectId}`);
      setProject(response.data);
    } catch {
      setProject(null);
    }
  }, [projectId]);

  const loadRepositories = useCallback(async () => {
    if (!projectId) return;

    setStatus("loading");
    try {
      const data = await listRepositories(projectId);
      setRepositories(data);

      if (data.length === 0) {
        setStatus("empty");
      } else {
        setStatus("ready");
        // If no repo selected, select the first one
        if (!selectedRepoId) {
          setSelectedRepoId(data[0].id);
          const newParams = new URLSearchParams(searchParams);
          newParams.set("repo", data[0].id);
          setSearchParams(newParams, { replace: true });
        }
      }
    } catch {
      setRepositories([]);
      setStatus("error");
    }
  }, [projectId, selectedRepoId, searchParams, setSearchParams]);

  const loadBranches = useCallback(async () => {
    if (!projectId || !selectedRepoId) return;
    try {
      const response = await apiClient.get(
        `/projects/${projectId}/repositories/${selectedRepoId}/branches`
      );
      const branchList = response.data.branches.map((b: { name: string }) => b.name);
      setBranches(branchList);
      const defaultBranch = response.data.default_branch;
      if (defaultBranch) {
        setCurrentBranch(defaultBranch);
      }
    } catch {
      setBranches([]);
    }
  }, [projectId, selectedRepoId]);

  const loadGitStatus = useCallback(async () => {
    if (!projectId || !selectedRepoId) return;
    try {
      const data = await getRepositoryStatus(projectId, selectedRepoId);
      setGitStatus(data);
    } catch {
      setGitStatus(null);
    }
  }, [projectId, selectedRepoId]);

  const loadToolTypes = useCallback(async () => {
    try {
      const data = await listToolTypes();
      setToolTypes(data);
    } catch {
      setToolTypes([]);
    }
  }, []);

  useEffect(() => {
    void loadProject();
    void loadRepositories();
    void loadToolTypes();
  }, [loadProject, loadRepositories, loadToolTypes]);

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

  const handleRepoChange = (repoId: string) => {
    setSelectedRepoId(repoId);
    const newParams = new URLSearchParams(searchParams);
    newParams.set("repo", repoId);
    newParams.delete("branch");
    newParams.delete("path");
    setSearchParams(newParams);
  };

  const selectedRepo = repositories.find((r) => r.id === selectedRepoId);

  return (
    <section className="repo-workspace">
      {project && (
        <WorkspaceHeader
          project={project}
          currentRepo={selectedRepo || null}
        />
      )}

      {status === "loading" && (
        <p className="muted">Loading repositories...</p>
      )}

      {status === "error" && (
        <div className="card stack">
          <p>Failed to load repositories</p>
          <button
            className="secondary-button"
            onClick={() => void loadRepositories()}
            type="button"
          >
            <Icon name="refresh" size="sm" />
            Retry
          </button>
        </div>
      )}

      {status === "empty" && (
        <div className="card stack">
          <p>No repositories in this project yet.</p>
          <Link
            className="primary-button"
            to={`/projects/${projectId}/settings/repositories`}
          >
            Manage Repositories
          </Link>
        </div>
      )}

      {status === "ready" && repositories.length > 0 && (
        <>
          {selectedRepoId && (
            <GitToolbar
              projectId={projectId!}
              repoId={selectedRepoId}
              currentBranch={currentBranch}
              branches={branches}
              onBranchChange={(branch) => {
                setCurrentBranch(branch);
                const newParams = new URLSearchParams(searchParams);
                newParams.set("branch", branch);
                setSearchParams(newParams);
              }}
              onRefresh={() => {
                void loadBranches();
                void loadGitStatus();
                window.dispatchEvent(new CustomEvent("refresh-file-tree"));
              }}
            />
          )}
          <div className="workspace-layout">
            <aside className="workspace-sidebar">
              <div className="sidebar-section">
                <label className="form-field">
                  Repository
                  <select
                    value={selectedRepoId || ""}
                    onChange={(e) => handleRepoChange(e.target.value)}
                  >
                    {repositories.map((repo) => (
                      <option key={repo.id} value={repo.id}>
                        {repo.name}
                      </option>
                    ))}
                  </select>
                </label>
              </div>

              {selectedRepoId && (
                <>
                  <FileBrowser
                    projectId={projectId!}
                    repoId={selectedRepoId}
                    gitStatus={gitStatus}
                  />
                {gitStatus && (
                  <CommitPanel
                    projectId={projectId!}
                    repoId={selectedRepoId}
                    modified={gitStatus.modified}
                    added={gitStatus.added}
                    deleted={gitStatus.deleted}
                    untracked={gitStatus.untracked}
                    onCommit={() => {
                      void loadGitStatus();
                      window.dispatchEvent(new CustomEvent("refresh-file-tree"));
                    }}
                  />
                )}
                {selectedRepoId && (
                  <InstanceList
                    projectId={projectId!}
                    repoId={selectedRepoId}
                    toolTypes={toolTypes}
                  />
                )}
              </>
            )}
          </aside>

          <main className="workspace-main">
            {selectedRepoId && (
              <FileEditor projectId={projectId!} repoId={selectedRepoId} />
            )}
          </main>
        </div>
      </>
      )}
    </section>
  );
};

// File Browser Component
const FileBrowser = ({
  projectId,
  repoId,
  gitStatus,
}: {
  projectId: string;
  repoId: string;
  gitStatus: GitStatus | null;
}) => {
  const [searchParams, setSearchParams] = useSearchParams();
  const [entries, setEntries] = useState<FileTreeEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

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

  const loadFiles = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const response = await apiClient.get(
        `/projects/${projectId}/repositories/${repoId}/files`,
        {
          params: {
            branch,
            path,
          },
        }
      );
      setEntries(response.data.entries || []);
    } catch {
      setError("Failed to load files");
    } finally {
      setLoading(false);
    }
  }, [projectId, repoId, branch, path]);

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

  // Listen for refresh events
  useEffect(() => {
    const handleRefresh = () => void loadFiles();
    window.addEventListener("refresh-file-tree", handleRefresh);
    return () => window.removeEventListener("refresh-file-tree", handleRefresh);
  }, [loadFiles]);

  const handleEntryClick = (entry: FileTreeEntry) => {
    if (entry.type === "directory") {
      const newParams = new URLSearchParams(searchParams);
      newParams.set("path", entry.path);
      setSearchParams(newParams);
    } else {
      const newParams = new URLSearchParams(searchParams);
      newParams.set("file", entry.path);
      setSearchParams(newParams);
    }
  };

  const navigateUp = () => {
    if (!path) return;
    const parentPath = path.split("/").slice(0, -1).join("/");
    const newParams = new URLSearchParams(searchParams);
    if (parentPath) {
      newParams.set("path", parentPath);
    } else {
      newParams.delete("path");
    }
    setSearchParams(newParams);
  };

  const getFileStatus = (filePath: string): string | null => {
    if (!gitStatus) return null;
    if (gitStatus.modified.includes(filePath)) return "modified";
    if (gitStatus.added.includes(filePath)) return "added";
    if (gitStatus.deleted.includes(filePath)) return "deleted";
    if (gitStatus.untracked.includes(filePath)) return "untracked";
    return null;
  };

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

  return (
    <div className="file-tree">
      {path && (
        <button className="tree-entry tree-up" onClick={navigateUp} type="button">
          <Icon name="folder" size="sm" /> ..
        </button>
      )}
      {entries.length === 0 && (
        <p className="muted">No files in this repository yet.</p>
      )}
      {entries.map((entry) => {
        const fileStatus = entry.type === "file" ? getFileStatus(entry.path) : null;
        return (
          <button
            key={entry.path}
            className={`tree-entry ${entry.type === "directory" ? "tree-directory" : "tree-file"} ${fileStatus || ""}`}
            onClick={() => handleEntryClick(entry)}
            type="button"
          >
            <Icon name={entry.type === "directory" ? "folder" : "file"} size="sm" /> {entry.name}
            {fileStatus && (
              <span className={`file-status-indicator ${fileStatus}`}>
                {fileStatus === "modified" && "M"}
                {fileStatus === "added" && "A"}
                {fileStatus === "deleted" && "D"}
                {fileStatus === "untracked" && "?"}
              </span>
            )}
          </button>
        );
      })}
    </div>
  );
};

