import { useEffect, useState } from "react";
import { invoke } from "@tauri-apps/api/core";

type DesktopStatus = "loading" | "ready" | "error";
type CheckStatus = "pass" | "warn" | "fail";

type DesktopCheck = {
  id: string;
  label: string;
  status: CheckStatus;
  detail: string;
};

type DesktopProfile = {
  identity: string;
  handle: string;
  display_name: string;
  rho_home: string;
  source: string;
};

type ProfileSelection = {
  identity?: string;
  rho_home?: string;
};

type CommandResult = {
  ok: boolean;
  code?: number;
  stdout: string;
  stderr: string;
};

type DesktopProject = {
  id: string;
  name: string;
  path: string;
  exists: boolean;
  is_git: boolean;
  is_rho: boolean;
  rho_project_id?: string;
  owner?: string;
  role: string;
  current_branch?: string;
  remote_url?: string;
  dirty: boolean;
  upstream?: string;
  ahead: number;
  behind: number;
  status_summary: string;
  warning?: string;
};

type FileEntry = {
  path: string;
  kind: string;
  status?: string;
};

type MemberInfo = {
  identity: string;
  handle: string;
  role: string;
};

type ParticipantInfo = {
  handle: string;
  identity?: string;
  display_name?: string;
  signing_fingerprint?: string;
  encryption_fingerprint?: string;
  proof_url?: string;
};

type RepoFileSummary = {
  path: string;
  title: string;
  summary: string;
};

type ToolInfo = {
  id: string;
  action_type?: string;
  owner?: string;
  approval_required: boolean;
  path: string;
};

type MessageInfo = {
  path: string;
  inbox: string;
  thread: string;
  kind: string;
  encrypted: boolean;
  signed: boolean;
  summary: string;
};

type PendingAction = {
  id: string;
  kind: string;
  actor?: string;
  summary: string;
  path: string;
};

type GitStatusEntry = {
  path: string;
  status: string;
};

type RepoDetail = {
  project: DesktopProject;
  files: FileEntry[];
  members: MemberInfo[];
  participants: ParticipantInfo[];
  policy_files: RepoFileSummary[];
  tools: ToolInfo[];
  messages: MessageInfo[];
  pending_actions: PendingAction[];
  status_entries: GitStatusEntry[];
};

export default function App() {
  const [status, setStatus] = useState<DesktopStatus>("loading");
  const [version, setVersion] = useState<string>("");
  const [error, setError] = useState<string>("");
  const [profiles, setProfiles] = useState<DesktopProfile[]>([]);
  const [selectedIdentity, setSelectedIdentity] = useState<string>("");
  const [checks, setChecks] = useState<DesktopCheck[]>([]);
  const [isChecking, setIsChecking] = useState<boolean>(false);
  const [actionResult, setActionResult] = useState<string>("");
  const [isSwitchingGh, setIsSwitchingGh] = useState<boolean>(false);
  const [isCheckingEnv, setIsCheckingEnv] = useState<boolean>(false);
  const [projects, setProjects] = useState<DesktopProject[]>([]);
  const [projectsError, setProjectsError] = useState<string>("");
  const [isLoadingProjects, setIsLoadingProjects] = useState<boolean>(false);
  const [isAddingProject, setIsAddingProject] = useState<boolean>(false);
  const [isCloningProject, setIsCloningProject] = useState<boolean>(false);
  const [localProjectPath, setLocalProjectPath] = useState<string>("");
  const [cloneUrl, setCloneUrl] = useState<string>("");
  const [cloneDestination, setCloneDestination] = useState<string>("");
  const [selectedProjectPath, setSelectedProjectPath] = useState<string>("");
  const [repoDetail, setRepoDetail] = useState<RepoDetail | null>(null);
  const [repoDetailError, setRepoDetailError] = useState<string>("");
  const [isLoadingRepoDetail, setIsLoadingRepoDetail] = useState<boolean>(false);

  useEffect(() => {
    const queryIdentity = new URLSearchParams(window.location.search).get("identity") ?? "";

    void Promise.all([
      invoke<string>("app_version"),
      invoke<DesktopProfile[]>("desktop_profiles")
    ])
      .then(([value, discoveredProfiles]) => {
        setVersion(value);
        setProfiles(discoveredProfiles);
        setSelectedIdentity(queryIdentity || discoveredProfiles[0]?.identity || "");
        setStatus("ready");
      })
      .catch((cause: unknown) => {
        setError(cause instanceof Error ? cause.message : String(cause));
        setStatus("error");
      });
  }, []);

  useEffect(() => {
    if (status !== "ready") {
      return;
    }
    void runChecks(selectedIdentity);
    void loadProjects(selectedIdentity);
    setSelectedProjectPath("");
    setRepoDetail(null);
  }, [selectedIdentity, status]);

  const selectedProfile = profiles.find((profile) => profile.identity === selectedIdentity);

  function selection(identity = selectedIdentity): ProfileSelection | undefined {
    const profile = profiles.find((candidate) => candidate.identity === identity);
    if (!profile && !identity) {
      return undefined;
    }
    return {
      identity: identity || profile?.identity,
      rho_home: profile?.rho_home
    };
  }

  async function runChecks(identity = selectedIdentity) {
    setIsChecking(true);
    try {
      const result = await invoke<DesktopCheck[]>("desktop_checks", {
        profile: selection(identity)
      });
      setChecks(result);
    } catch (cause) {
      setError(cause instanceof Error ? cause.message : String(cause));
      setStatus("error");
    } finally {
      setIsChecking(false);
    }
  }

  async function openProfileWindow() {
    await invoke("open_profile_window", {
      profile: selection()
    });
  }

  async function switchGhProfile() {
    setIsSwitchingGh(true);
    try {
      const result = await invoke<CommandResult>("switch_github_profile", {
        profile: selection()
      });
      setActionResult(formatCommandResult("rho gh switch", result));
      await runChecks();
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsSwitchingGh(false);
    }
  }

  async function checkProfileEnv() {
    setIsCheckingEnv(true);
    try {
      const result = await invoke<CommandResult>("profile_rho_env", {
        profile: selection()
      });
      setActionResult(formatCommandResult("rho env status", result));
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCheckingEnv(false);
    }
  }

  async function loadProjects(identity = selectedIdentity) {
    setIsLoadingProjects(true);
    setProjectsError("");
    try {
      const result = await invoke<DesktopProject[]>("desktop_projects", {
        profile: selection(identity)
      });
      setProjects(result);
      if (selectedProjectPath && !result.some((project) => project.path === selectedProjectPath)) {
        setSelectedProjectPath("");
        setRepoDetail(null);
      }
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsLoadingProjects(false);
    }
  }

  async function addLocalProject() {
    if (!localProjectPath.trim()) {
      setProjectsError("Enter a local repository path first.");
      return;
    }
    setIsAddingProject(true);
    setProjectsError("");
    try {
      const project = await invoke<DesktopProject>("add_local_project", {
        path: localProjectPath,
        profile: selection()
      });
      setActionResult(`Added ${project.name}`);
      setLocalProjectPath("");
      await loadProjects();
      await selectProject(project.path);
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsAddingProject(false);
    }
  }

  async function cloneProject() {
    if (!cloneUrl.trim()) {
      setProjectsError("Enter a GitHub repository URL first.");
      return;
    }
    setIsCloningProject(true);
    setProjectsError("");
    try {
      const project = await invoke<DesktopProject>("clone_github_project", {
        url: cloneUrl,
        destination: cloneDestination || undefined,
        profile: selection()
      });
      setActionResult(`Cloned ${project.name}`);
      setCloneUrl("");
      setCloneDestination("");
      await loadProjects();
      await selectProject(project.path);
    } catch (cause) {
      setProjectsError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsCloningProject(false);
    }
  }

  async function selectProject(path: string) {
    setSelectedProjectPath(path);
    setRepoDetailError("");
    setIsLoadingRepoDetail(true);
    try {
      const detail = await invoke<RepoDetail>("repo_detail", {
        path,
        profile: selection()
      });
      setRepoDetail(detail);
    } catch (cause) {
      setRepoDetail(null);
      setRepoDetailError(cause instanceof Error ? cause.message : String(cause));
    } finally {
      setIsLoadingRepoDetail(false);
    }
  }

  async function openProjectFolder(path: string) {
    try {
      const result = await invoke<CommandResult>("open_project_folder", { path });
      if (!result.ok) {
        setActionResult(formatCommandResult("open folder", result));
      }
    } catch (cause) {
      setActionResult(cause instanceof Error ? cause.message : String(cause));
    }
  }

  function formatCommandResult(label: string, result: CommandResult): string {
    const body = [result.stdout, result.stderr].filter(Boolean).join("\n");
    const statusText = result.ok ? "ok" : `exit ${result.code ?? "unknown"}`;
    return `${label}: ${statusText}${body ? `\n${body}` : ""}`;
  }

  function shortPath(path: string): string {
    return path.length > 70 ? `...${path.slice(-67)}` : path;
  }

  return (
    <main className="app-shell">
      <section className="workspace">
        <header className="topbar">
          <div>
            <h1>Rho</h1>
            <p>Local-first collaboration for protected agent workflows.</p>
          </div>
          <span className="status" data-state={status}>
            {status === "ready" ? `v${version}` : status}
          </span>
        </header>

        <div className="profile-toolbar">
          <label>
            <span>Profile</span>
            <select
              value={selectedIdentity}
              onChange={(event) => setSelectedIdentity(event.target.value)}
            >
              {profiles.length === 0 ? (
                <option value="">No local profiles found</option>
              ) : null}
              {profiles.map((profile) => (
                <option key={profile.identity} value={profile.identity}>
                  {profile.handle} - {profile.source}
                </option>
              ))}
            </select>
          </label>
          <div className="profile-actions">
            <button type="button" onClick={() => void runChecks()} disabled={isChecking}>
              {isChecking ? "Checking" : "Recheck"}
            </button>
            <button
              type="button"
              onClick={() => void switchGhProfile()}
              disabled={isSwitchingGh || !selectedIdentity}
            >
              {isSwitchingGh ? "Switching" : "Switch gh"}
            </button>
            <button
              type="button"
              onClick={() => void checkProfileEnv()}
              disabled={isCheckingEnv || !selectedIdentity}
            >
              {isCheckingEnv ? "Checking" : "Check Rho Env"}
            </button>
            <button type="button" onClick={() => void openProfileWindow()}>
              New Profile Window
            </button>
          </div>
        </div>

        {selectedProfile ? (
          <section className="profile-summary">
            <div>
              <h2>{selectedProfile.display_name}</h2>
              <p>{selectedProfile.identity}</p>
            </div>
            <code>{selectedProfile.rho_home}</code>
          </section>
        ) : null}

        <section className="checks" aria-label="Profile readiness checks">
          {checks.map((check) => (
            <article key={check.id} data-state={check.status}>
              <div>
                <h2>{check.label}</h2>
                <p>{check.detail || "No detail returned"}</p>
              </div>
              <span>{check.status}</span>
            </article>
          ))}
        </section>

        {actionResult ? <pre className="action-result">{actionResult}</pre> : null}

        <section className="projects-panel">
          <div className="section-heading">
            <div>
              <h2>Projects</h2>
              <p>Repos tracked for this profile window.</p>
            </div>
            <button type="button" onClick={() => void loadProjects()} disabled={isLoadingProjects}>
              {isLoadingProjects ? "Refreshing" : "Refresh"}
            </button>
          </div>

          <div className="project-actions">
            <label>
              <span>Local repo path</span>
              <input
                value={localProjectPath}
                onChange={(event) => setLocalProjectPath(event.target.value)}
                placeholder="~/dev/rho-project"
              />
            </label>
            <button
              type="button"
              onClick={() => void addLocalProject()}
              disabled={isAddingProject}
            >
              {isAddingProject ? "Adding" : "Add Repo"}
            </button>
          </div>

          <div className="project-actions">
            <label>
              <span>GitHub repo URL</span>
              <input
                value={cloneUrl}
                onChange={(event) => setCloneUrl(event.target.value)}
                placeholder="https://github.com/org/repo"
              />
            </label>
            <label>
              <span>Destination</span>
              <input
                value={cloneDestination}
                onChange={(event) => setCloneDestination(event.target.value)}
                placeholder="Default: ~/.rho/projects/repo"
              />
            </label>
            <button
              type="button"
              onClick={() => void cloneProject()}
              disabled={isCloningProject}
            >
              {isCloningProject ? "Cloning" : "Clone"}
            </button>
          </div>

          {projectsError ? <p className="error">{projectsError}</p> : null}

          {projects.length === 0 ? (
            <div className="empty-state">
              <h2>No projects yet</h2>
              <p>Add a local git repo, clone a GitHub repo, or set up a new Rho repo from here.</p>
            </div>
          ) : (
            <div className="project-grid">
              {projects.map((project) => (
                <article
                  key={project.id}
                  className="project-card"
                  data-state={project.warning ? "warn" : project.dirty ? "dirty" : "pass"}
                >
                  <div className="project-card-main">
                    <div>
                      <h2>{project.name}</h2>
                      <p>{project.rho_project_id || project.path}</p>
                    </div>
                    <span>{project.role}</span>
                  </div>
                  <div className="project-meta">
                    <span>{project.is_rho ? "rho repo" : "not rho"}</span>
                    <span>{project.current_branch || "no branch"}</span>
                    <span>{project.status_summary}</span>
                    {project.upstream ? <span>{project.upstream}</span> : null}
                  </div>
                  {project.owner ? <p>Owner: {project.owner}</p> : null}
                  {project.remote_url ? <p>{project.remote_url}</p> : null}
                  {project.warning ? <p className="project-warning">{project.warning}</p> : null}
                  <div className="project-card-actions">
                    <button
                      type="button"
                      onClick={() => void openProjectFolder(project.path)}
                      disabled={!project.exists}
                    >
                      Open Folder
                    </button>
                    <button
                      type="button"
                      onClick={() => void selectProject(project.path)}
                      disabled={!project.exists || isLoadingRepoDetail}
                    >
                      {selectedProjectPath === project.path ? "Refresh Repo" : "Open Repo"}
                    </button>
                    <button
                      type="button"
                      onClick={() => void selectProject(project.path)}
                      disabled={!project.exists || isLoadingRepoDetail}
                    >
                      Messages
                    </button>
                  </div>
                </article>
              ))}
            </div>
          )}
        </section>

        {repoDetailError ? <p className="error">{repoDetailError}</p> : null}

        {isLoadingRepoDetail ? (
          <section className="repo-detail-panel">
            <div className="section-heading">
              <div>
                <h2>Loading Repository</h2>
                <p>{selectedProjectPath}</p>
              </div>
            </div>
          </section>
        ) : null}

        {repoDetail ? (
          <section className="repo-detail-panel">
            <div className="section-heading">
              <div>
                <h2>{repoDetail.project.name}</h2>
                <p>{repoDetail.project.rho_project_id || repoDetail.project.path}</p>
              </div>
              <div className="detail-actions">
                <button
                  type="button"
                  onClick={() => void selectProject(repoDetail.project.path)}
                  disabled={isLoadingRepoDetail}
                >
                  Refresh Detail
                </button>
                <button
                  type="button"
                  onClick={() => void openProjectFolder(repoDetail.project.path)}
                >
                  Open Folder
                </button>
              </div>
            </div>

            <div className="detail-summary">
              <span>{repoDetail.project.current_branch || "no branch"}</span>
              <span>{repoDetail.project.status_summary}</span>
              <span>{repoDetail.members.length} member(s)</span>
              <span>{repoDetail.messages.length} message file(s)</span>
              <span>{repoDetail.pending_actions.length} pending action(s)</span>
            </div>

            <div className="detail-grid">
              <section className="detail-block">
                <h2>Files</h2>
                <div className="file-list">
                  {repoDetail.files.slice(0, 80).map((file) => (
                    <div key={file.path} className="file-row">
                      <span>{file.status || file.kind}</span>
                      <code>{shortPath(file.path)}</code>
                    </div>
                  ))}
                  {repoDetail.files.length === 0 ? <p>No files found.</p> : null}
                </div>
              </section>

              <section className="detail-block">
                <h2>Members</h2>
                <div className="compact-list">
                  {repoDetail.members.map((member) => (
                    <div key={member.identity}>
                      <strong>{member.handle}</strong>
                      <span>{member.role}</span>
                      <code>{member.identity}</code>
                    </div>
                  ))}
                  {repoDetail.members.length === 0 ? <p>No membership file found.</p> : null}
                </div>
              </section>

              <section className="detail-block">
                <h2>Participants</h2>
                <div className="compact-list">
                  {repoDetail.participants.map((participant) => (
                    <div key={participant.handle}>
                      <strong>{participant.display_name || participant.handle}</strong>
                      <span>{participant.handle}</span>
                      {participant.signing_fingerprint ? (
                        <code>sign {participant.signing_fingerprint}</code>
                      ) : null}
                      {participant.encryption_fingerprint ? (
                        <code>enc {participant.encryption_fingerprint}</code>
                      ) : null}
                    </div>
                  ))}
                  {repoDetail.participants.length === 0 ? <p>No participant bundles found.</p> : null}
                </div>
              </section>

              <section className="detail-block">
                <h2>Policy</h2>
                <div className="compact-list">
                  {repoDetail.policy_files.map((file) => (
                    <div key={file.path}>
                      <strong>{file.title}</strong>
                      <span>{file.summary}</span>
                      <code>{file.path}</code>
                    </div>
                  ))}
                  {repoDetail.policy_files.length === 0 ? <p>No policy files found.</p> : null}
                </div>
              </section>

              <section className="detail-block">
                <h2>Tools</h2>
                <div className="compact-list">
                  {repoDetail.tools.map((tool) => (
                    <div key={tool.path}>
                      <strong>{tool.id}</strong>
                      <span>{tool.action_type || "action"}</span>
                      <span>{tool.approval_required ? "approval required" : "no approval"}</span>
                      <code>{tool.path}</code>
                    </div>
                  ))}
                  {repoDetail.tools.length === 0 ? <p>No tools found.</p> : null}
                </div>
              </section>

              <section className="detail-block">
                <h2>Messages</h2>
                <div className="compact-list">
                  {repoDetail.messages.map((message) => (
                    <div key={message.path}>
                      <strong>{message.kind}</strong>
                      <span>{message.summary}</span>
                      <span>
                        {message.inbox} / {message.thread}
                      </span>
                      <code>{message.path}</code>
                    </div>
                  ))}
                  {repoDetail.messages.length === 0 ? <p>No inbox messages for this profile.</p> : null}
                </div>
              </section>
            </div>

            <section className="detail-block pending-block">
              <h2>Pending Actions</h2>
              <div className="compact-list">
                {repoDetail.pending_actions.map((action) => (
                  <div key={action.id}>
                    <strong>{action.kind}</strong>
                    <span>{action.summary}</span>
                    {action.actor ? <span>{action.actor}</span> : null}
                    <code>{action.path}</code>
                  </div>
                ))}
                {repoDetail.pending_actions.length === 0 ? <p>No pending actions detected.</p> : null}
              </div>
            </section>
          </section>
        ) : null}

        {status === "error" ? <p className="error">{error}</p> : null}
      </section>
    </main>
  );
}
