import { defineStore } from 'pinia';
import { ref } from 'vue';
import type {
  CreateWorktreeRequest,
  CreateWorktreeResponse,
  DiscoverReposResponse,
  RepoResponse,
  ReposListResponse,
  RepoSummary,
  WorktreeSummary,
  WorktreesListResponse,
} from '@arboretum/shared';
import { api } from '../lib/api';
import { wsClient, type WorktreeEvent } from '../lib/ws-client';

export const useWorktreesStore = defineStore('worktrees', () => {
  const repos = ref<RepoSummary[]>([]);
  const worktrees = ref<WorktreeSummary[]>([]);
  const loading = ref(false);
  const loadError = ref<string | null>(null);
  let unsubscribe: (() => void) | null = null;

  function upsertRepo(repo: RepoSummary): void {
    const idx = repos.value.findIndex((r) => r.id === repo.id);
    if (idx >= 0) repos.value.splice(idx, 1, repo);
    else repos.value.push(repo);
  }
  function removeRepoLocal(id: string): void {
    repos.value = repos.value.filter((r) => r.id !== id);
    worktrees.value = worktrees.value.filter((w) => w.repoId !== id);
  }
  function upsertWorktree(wt: WorktreeSummary): void {
    const idx = worktrees.value.findIndex((w) => w.path === wt.path);
    if (idx >= 0) worktrees.value.splice(idx, 1, wt);
    else worktrees.value.push(wt);
  }
  function removeWorktreeLocal(path: string): void {
    worktrees.value = worktrees.value.filter((w) => w.path !== path);
  }

  function onEvent(e: WorktreeEvent): void {
    if (e.type === 'repo_update') upsertRepo(e.repo);
    else if (e.type === 'repo_removed') removeRepoLocal(e.repoId);
    else if (e.type === 'worktree_update') upsertWorktree(e.worktree);
    else removeWorktreeLocal(e.path);
  }

  function worktreesForRepo(repoId: string): WorktreeSummary[] {
    return worktrees.value
      .filter((w) => w.repoId === repoId)
      .sort((a, b) => Number(b.isMain) - Number(a.isMain) || a.path.localeCompare(b.path));
  }

  async function fetchAll(): Promise<void> {
    loading.value = true;
    loadError.value = null;
    try {
      const [r, w] = await Promise.all([
        api.get<ReposListResponse>('/api/v1/repos'),
        api.get<WorktreesListResponse>('/api/v1/worktrees'),
      ]);
      repos.value = r.repos;
      worktrees.value = w.worktrees;
    } catch (err) {
      loadError.value = err instanceof Error ? err.message : String(err);
    } finally {
      loading.value = false;
    }
  }

  async function refreshRepoWorktrees(repoId: string): Promise<void> {
    const w = await api.get<WorktreesListResponse>(`/api/v1/repos/${repoId}/worktrees`);
    for (const wt of w.worktrees) upsertWorktree(wt);
  }

  async function addRepo(path: string, label?: string): Promise<RepoSummary> {
    const res = await api.post<RepoResponse>('/api/v1/repos', { path, ...(label ? { label } : {}) });
    upsertRepo(res.repo);
    await refreshRepoWorktrees(res.repo.id);
    return res.repo;
  }

  async function removeRepo(id: string): Promise<void> {
    await api.delete<{ ok: true }>(`/api/v1/repos/${id}`);
    removeRepoLocal(id);
  }

  /** Masque/ré-affiche un repo (persiste `hidden` côté serveur ; émis aussi par WS). */
  async function setHidden(id: string, hidden: boolean): Promise<void> {
    const res = await api.patch<RepoResponse>(`/api/v1/repos/${id}`, { hidden });
    upsertRepo(res.repo);
  }

  /** Lance un scan de découverte ; les nouveaux repos arrivent par WS, on resynchronise par sûreté. */
  async function discover(): Promise<DiscoverReposResponse> {
    const res = await api.post<DiscoverReposResponse>('/api/v1/repos/discover');
    await fetchAll();
    return res;
  }

  async function createWorktree(repoId: string, req: CreateWorktreeRequest): Promise<CreateWorktreeResponse> {
    const res = await api.post<CreateWorktreeResponse>(`/api/v1/repos/${repoId}/worktrees`, req);
    upsertWorktree(res.worktree);
    return res;
  }

  async function deleteWorktree(repoId: string, path: string, force: boolean): Promise<void> {
    await api.delete<{ ok: true }>(`/api/v1/repos/${repoId}/worktrees?path=${encodeURIComponent(path)}&force=${force}`);
    removeWorktreeLocal(path);
  }

  async function prune(repoId: string): Promise<void> {
    await api.post<{ ok: true }>(`/api/v1/repos/${repoId}/worktrees/prune`);
    await refreshRepoWorktrees(repoId);
  }

  function startRealtime(): void {
    unsubscribe ??= wsClient.subscribeWorktrees(onEvent);
  }
  function stopRealtime(): void {
    unsubscribe?.();
    unsubscribe = null;
  }

  return {
    repos,
    worktrees,
    loading,
    loadError,
    worktreesForRepo,
    fetchAll,
    addRepo,
    removeRepo,
    setHidden,
    discover,
    refreshRepoWorktrees,
    createWorktree,
    deleteWorktree,
    prune,
    startRealtime,
    stopRealtime,
  };
});
