import { useCallback, useEffect, useState } from "react";
import { EmptyState, ErrorState, LoadingState } from "../components/data-states";
import { Icon } from "../components/icon";
import { useMobileViewport } from "../hooks/use-mobile-viewport";

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 MobileTab = "files" | "editor" | "git" | "terminal";

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 isMobile = useMobileViewport();
  const [mobileTab, setMobileTab] = useState<MobileTab>("files");

  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" && (
        <LoadingState message="Loading repositories..." />
      )}

      {status === "error" && (
        <ErrorState message="Failed to load repositories" onRetry={() => void loadRepositories()} />
      )}

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

      {status === "ready" && repositories.length > 0 && (
        <>
          {isMobile ? (
            // Mobile Layout
            <div className="mobile-workspace">
              <div className="mobile-workspace-header">
                <select
                  value={selectedRepoId || ""}
                  onChange={(e) => handleRepoChange(e.target.value)}
                  className="mobile-repo-selector"
                >
                  {repositories.map((repo) => (
                    <option key={repo.id} value={repo.id}>
                      {repo.name}
                    </option>
                  ))}
                </select>
                {selectedRepoId && (
                  <select
                    value={currentBranch}
                    onChange={(e) => {
                      const branch = e.target.value;
                      setCurrentBranch(branch);
                      const newParams = new URLSearchParams(searchParams);
                      newParams.set("branch", branch);
                      setSearchParams(newParams);
                    }}
                    className="mobile-branch-selector"
                  >
                    {branches.map((branch) => (
                      <option key={branch} value={branch}>
                        {branch}
                      </option>
                    ))}
                  </select>
                )}
              </div>

              <div className="mobile-workspace-content">
                {mobileTab === "files" && selectedRepoId && (
                  <FileBrowser
                    projectId={projectId!}
                    repoId={selectedRepoId}
                    gitStatus={gitStatus}
                  />
                )}
                {mobileTab === "editor" && selectedRepoId && (
                  <FileEditor projectId={projectId!} repoId={selectedRepoId} />
                )}
                {mobileTab === "git" && selectedRepoId && gitStatus && (
                  <div className="mobile-git-view">
                    <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"));
                      }}
                    />
                  </div>
                )}
                {mobileTab === "terminal" && selectedRepoId && (
                  <InstanceList
                    projectId={projectId!}
                    repoId={selectedRepoId}
                    projectName={project?.name}
                    repoName={repositories.find((r) => r.id === selectedRepoId)?.name}
                    toolTypes={toolTypes}
                  />
                )}
              </div>

              <div className="mobile-workspace-tabs">
                <button
                  className={`mobile-workspace-tab ${mobileTab === "files" ? "active" : ""}`}
                  onClick={() => setMobileTab("files")}
                  type="button"
                >
                  <Icon name="folder" size="sm" />
                  <span>Files</span>
                </button>
                <button
                  className={`mobile-workspace-tab ${mobileTab === "editor" ? "active" : ""}`}
                  onClick={() => setMobileTab("editor")}
                  type="button"
                >
                  <Icon name="edit" size="sm" />
                  <span>Editor</span>
                </button>
                <button
                  className={`mobile-workspace-tab ${mobileTab === "git" ? "active" : ""}`}
                  onClick={() => setMobileTab("git")}
                  type="button"
                >
                  <Icon name="branch" size="sm" />
                  <span>Git</span>
                </button>
                <button
                  className={`mobile-workspace-tab ${mobileTab === "terminal" ? "active" : ""}`}
                  onClick={() => setMobileTab("terminal")}
                  type="button"
                >
                  <Icon name="terminal" size="sm" />
                  <span>Terminal</span>
                </button>
              </div>
            </div>
          ) : (
            // Desktop Layout
            <>
              {selectedRepoId && (
                <GitToolbar
                  projectId={projectId!}
                  repoId={selectedRepoId}
                  currentBranch={currentBranch}
                  branches={branches}
                  hasRemote={Boolean(selectedRepo?.remote_url)}
                  isMirror={Boolean(selectedRepo?.is_mirror)}
                  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"));
                          }}
                        />
                      )}
                      <InstanceList
                        projectId={projectId!}
                        repoId={selectedRepoId}
                        projectName={project?.name}
                        repoName={repositories.find((r) => r.id === selectedRepoId)?.name}
                        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 && (
        <EmptyState message="No files in this repository yet." />
      )}
      {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>
  );
};
