/**
 * Repository slice - manages repository grouping state (worktree support).
 */

import { api } from '@renderer/api';
import { createLogger } from '@shared/utils/logger';

import { getSessionResetState } from '../utils/stateResetHelpers';

import type { AppState } from '../types';
import type { RepositoryGroup } from '@renderer/types/data';
import type { StateCreator } from 'zustand';

const logger = createLogger('Store:repository');
const FETCH_REPOSITORY_GROUPS_TIMEOUT_MS = 30_000;

async function withTimeout<T>(promise: Promise<T>, timeoutMs: number, label: string): Promise<T> {
  let timeoutId: ReturnType<typeof setTimeout> | null = null;
  const timeoutPromise = new Promise<T>((_resolve, reject) => {
    timeoutId = setTimeout(
      () => reject(new Error(`${label} timed out after ${timeoutMs}ms`)),
      timeoutMs
    );
  });
  try {
    return await Promise.race([promise, timeoutPromise]);
  } finally {
    if (timeoutId) clearTimeout(timeoutId);
  }
}

// =============================================================================
// Slice Interface
// =============================================================================

export interface RepositorySlice {
  // State
  repositoryGroups: RepositoryGroup[];
  selectedRepositoryId: string | null;
  selectedWorktreeId: string | null;
  repositoryGroupsLoading: boolean;
  repositoryGroupsError: string | null;
  viewMode: 'flat' | 'grouped';

  // Actions
  fetchRepositoryGroups: () => Promise<void>;
  selectRepository: (repositoryId: string) => void;
  selectWorktree: (worktreeId: string) => void;
  setViewMode: (mode: 'flat' | 'grouped') => void;
}

// =============================================================================
// Slice Creator
// =============================================================================

export const createRepositorySlice: StateCreator<AppState, [], [], RepositorySlice> = (
  set,
  get
) => ({
  // Initial state
  repositoryGroups: [],
  selectedRepositoryId: null,
  selectedWorktreeId: null,
  repositoryGroupsLoading: false,
  repositoryGroupsError: null,
  viewMode: 'grouped', // Default to grouped view

  // Fetch all repository groups (projects grouped by git repo)
  fetchRepositoryGroups: async () => {
    // Guard: prevent concurrent fetches (component mount + centralized init chain)
    if (get().repositoryGroupsLoading) return;
    const startedAt = Date.now();
    set({ repositoryGroupsLoading: true, repositoryGroupsError: null });
    try {
      const groups = await withTimeout(
        api.getRepositoryGroups(),
        FETCH_REPOSITORY_GROUPS_TIMEOUT_MS,
        'get-repository-groups'
      );
      // Already sorted by most recent session in the scanner
      set({ repositoryGroups: groups, repositoryGroupsLoading: false });
      const ms = Date.now() - startedAt;
      if (ms >= 2000) {
        logger.warn(`fetchRepositoryGroups slow ms=${ms} count=${groups.length}`);
      }
    } catch (error) {
      const ms = Date.now() - startedAt;
      logger.warn(
        `fetchRepositoryGroups failed ms=${ms}: ${error instanceof Error ? error.message : String(error)}`
      );
      set({
        repositoryGroupsError:
          error instanceof Error ? error.message : 'Failed to fetch repository groups',
        repositoryGroupsLoading: false,
      });
    }
  },

  // Select a repository group and auto-select a worktree
  selectRepository: (repositoryId: string) => {
    const { repositoryGroups } = get();
    const repo = repositoryGroups.find((r) => r.id === repositoryId);

    if (!repo) {
      logger.warn('Repository not found:', repositoryId);
      return;
    }

    // Auto-select worktree:
    // 1. Prefer the "Default" worktree (isMainWorktree = true)
    // 2. Otherwise, select the first worktree (already sorted by most recent)
    const defaultWorktree = repo.worktrees.find((w) => w.isMainWorktree);
    const worktreeToSelect = defaultWorktree ?? repo.worktrees[0];

    if (worktreeToSelect) {
      set({
        selectedRepositoryId: repositoryId,
        selectedWorktreeId: worktreeToSelect.id,
        selectedProjectId: worktreeToSelect.id,
        activeProjectId: worktreeToSelect.id,
        ...getSessionResetState(),
      });
      // Fetch sessions for this worktree
      void get().fetchSessionsInitial(worktreeToSelect.id);
    } else {
      // No worktrees available (shouldn't happen normally)
      set({
        selectedRepositoryId: repositoryId,
        selectedWorktreeId: null,
        ...getSessionResetState(),
      });
    }
  },

  // Select a worktree within a repository group
  selectWorktree: (worktreeId: string) => {
    set({
      selectedWorktreeId: worktreeId,
      selectedProjectId: worktreeId,
      activeProjectId: worktreeId,
      ...getSessionResetState(),
    });

    // Fetch sessions for this worktree
    void get().fetchSessionsInitial(worktreeId);
  },

  // Toggle between flat and grouped view modes
  setViewMode: (mode: 'flat' | 'grouped') => {
    set({
      viewMode: mode,
      selectedRepositoryId: null,
      selectedWorktreeId: null,
      selectedProjectId: null,
      ...getSessionResetState(),
    });

    // Fetch the appropriate data for the new mode
    if (mode === 'grouped') {
      void get().fetchRepositoryGroups();
    } else {
      void get().fetchProjects();
    }
  },
});
