/**
 * Workspace store — project/group CRUD, aggregates, and DB loading.
 *
 * Single source of truth for projects and groups state.
 * App.svelte is a thin view layer that reads from this store.
 */

import { appRpc } from './rpc.ts';
import { trackProject } from './health-store.svelte.ts';

// ── Types ─────────────────────────────────────────────────────────────────

type AgentStatus = 'running' | 'idle' | 'stalled';

export interface Project {
  id: string;
  name: string;
  cwd: string;
  accent: string;
  status: AgentStatus;
  costUsd: number;
  tokens: number;
  messages: Array<{ id: number; role: string; content: string }>;
  provider?: string;
  profile?: string;
  model?: string;
  contextPct?: number;
  burnRate?: number;
  groupId?: string;
  cloneOf?: string;
  worktreeBranch?: string;
  mainRepoPath?: string;
  cloneIndex?: number;
}

export interface Group {
  id: string;
  name: string;
  icon: string;
  position: number;
  hasNew?: boolean;
}

export interface WizardResult {
  id: string; name: string; cwd: string; provider?: string; model?: string;
  systemPrompt?: string; autoStart?: boolean; groupId?: string;
  useWorktrees?: boolean; shell?: string; icon?: string; color?: string;
  modelConfig?: Record<string, unknown>;
}

// ── Accent colors ─────────────────────────────────────────────────────────

const ACCENTS = [
  'var(--ctp-mauve)', 'var(--ctp-sapphire)', 'var(--ctp-teal)',
  'var(--ctp-peach)', 'var(--ctp-pink)', 'var(--ctp-lavender)',
  'var(--ctp-green)', 'var(--ctp-blue)', 'var(--ctp-flamingo)',
];

// ── State ─────────────────────────────────────────────────────────────────

let projects = $state<Project[]>([]);
let groups = $state<Group[]>([
  { id: 'dev', name: 'Development', icon: '1', position: 0 },
]);
let activeGroupId = $state('dev');
let previousGroupId = $state<string | null>(null);

// ── Derived (exposed as getter functions — modules cannot export $derived) ──

export function getMountedGroupIds(): Set<string> {
  return new Set([activeGroupId, ...(previousGroupId ? [previousGroupId] : [])]);
}
export function getActiveGroup(): Group {
  return groups.find(g => g.id === activeGroupId) ?? groups[0];
}
export function getFilteredProjects(): Project[] {
  return projects.filter(p => (p.groupId ?? 'dev') === activeGroupId);
}
export function getTotalCostDerived(): number {
  return projects.reduce((s, p) => s + p.costUsd, 0);
}
export function getTotalTokensDerived(): number {
  return projects.reduce((s, p) => s + p.tokens, 0);
}

// ── Getters/setters for state ─────────────────────────────────────────────

export function getProjects(): Project[] { return projects; }
export function setProjects(p: Project[]): void { projects = p; }
export function getGroups(): Group[] { return groups; }
export function setGroups(g: Group[]): void { groups = g; }
export function getActiveGroupId(): string { return activeGroupId; }

export function setActiveGroup(id: string | undefined): void {
  if (!id) return;
  if (activeGroupId !== id) previousGroupId = activeGroupId;
  activeGroupId = id;
  appRpc.request["settings.set"]({ key: 'active_group', value: id }).catch(console.error);
}

// ── Project CRUD ──────────────────────────────────────────────────────────

export async function addProject(name: string, cwd: string): Promise<void> {
  if (!name.trim() || !cwd.trim()) return;
  const id = `p-${Date.now()}`;
  const accent = ACCENTS[projects.length % ACCENTS.length];
  const project: Project = {
    id, name: name.trim(), cwd: cwd.trim(), accent,
    status: 'idle', costUsd: 0, tokens: 0, messages: [],
    provider: 'claude', groupId: activeGroupId,
  };
  projects = [...projects, project];
  trackProject(id);
  await appRpc.request['settings.setProject']({
    id, config: JSON.stringify(project),
  }).catch(console.error);
}

/** Add a project from the ProjectWizard result. */
export function addProjectFromWizard(result: WizardResult): void {
  const accent = result.color || ACCENTS[projects.length % ACCENTS.length];
  const gid = result.groupId ?? activeGroupId;
  const project: Project = {
    id: result.id,
    name: result.name,
    cwd: result.cwd,
    accent,
    status: 'idle',
    costUsd: 0,
    tokens: 0,
    messages: [],
    provider: result.provider ?? 'claude',
    model: result.model,
    groupId: gid,
  };
  projects = [...projects, project];
  trackProject(project.id);

  // Persist full config including shell, icon, modelConfig etc.
  const persistConfig = {
    id: result.id, name: result.name, cwd: result.cwd, accent,
    provider: result.provider ?? 'claude', model: result.model,
    groupId: gid, shell: result.shell, icon: result.icon,
    useWorktrees: result.useWorktrees, systemPrompt: result.systemPrompt,
    autoStart: result.autoStart, modelConfig: result.modelConfig,
  };
  appRpc.request['settings.setProject']({
    id: project.id,
    config: JSON.stringify(persistConfig),
  }).catch(console.error);
}

export async function deleteProject(projectId: string): Promise<void> {
  projects = projects.filter(p => p.id !== projectId);
  await appRpc.request['settings.deleteProject']({ id: projectId }).catch(console.error);
}

export function cloneCountForProject(projectId: string): number {
  return projects.filter(p => p.cloneOf === projectId).length;
}

export function handleClone(projectId: string, branch: string): void {
  const source = projects.find(p => p.id === projectId);
  if (!source) return;
  const branchName = branch || `feature/clone-${Date.now()}`;
  appRpc.request["project.clone"]({ projectId, branchName }).then((result) => {
    if (result.ok && result.project) {
      const cloneConfig = JSON.parse(result.project.config) as Project;
      projects = [...projects, { ...cloneConfig, status: 'idle', costUsd: 0, tokens: 0, messages: [] }];
    } else {
      console.error('[clone]', result.error);
    }
  }).catch(console.error);
}

// ── Group CRUD ────────────────────────────────────────────────────────────

export async function addGroup(name: string): Promise<void> {
  if (!name.trim()) return;
  const id = `grp-${Date.now()}`;
  const position = groups.length;
  const group: Group = { id, name: name.trim(), icon: String(position + 1), position };
  groups = [...groups, group];
  await appRpc.request['groups.create']({ id, name: name.trim(), icon: group.icon, position }).catch(console.error);
}

// ── DB loading ────────────────────────────────────────────────────────────

/** Load groups from DB, then apply saved active_group. */
export async function loadGroupsFromDb(): Promise<void> {
  try {
    const { groups: dbGroups } = await appRpc.request["groups.list"]({}) as { groups: Group[] };
    if (dbGroups.length > 0) groups = dbGroups;
    const { value } = await appRpc.request["settings.get"]({ key: 'active_group' }) as { value: string | null };
    if (value && groups.some(g => g.id === value)) activeGroupId = value;
  } catch (err) { console.error('[workspace] loadGroups error:', err); }
}

/** Load projects from DB. */
export async function loadProjectsFromDb(): Promise<void> {
  try {
    const { projects: dbProjects } = await appRpc.request["settings.getProjects"]({}) as {
      projects: Array<{ id: string; config: string }>;
    };
    if (dbProjects.length > 0) {
      const loaded: Project[] = dbProjects.flatMap(({ config }) => {
        try {
          const p = JSON.parse(config) as Project;
          return [{
            ...p,
            status: p.status ?? 'idle',
            costUsd: p.costUsd ?? 0,
            tokens: p.tokens ?? 0,
            messages: p.messages ?? [],
          }];
        } catch { return []; }
      });
      if (loaded.length > 0) projects = loaded;
    }
  } catch (err) { console.error('[workspace] loadProjects error:', err); }
}

/** Track all loaded projects in health store. */
export function trackAllProjects(): void {
  for (const p of projects) trackProject(p.id);
}

// ── Aggregates (legacy function API — prefer derived exports) ─────────────

export function getTotalCost(): number { return projects.reduce((s, p) => s + p.costUsd, 0); }
export function getTotalTokens(): number { return projects.reduce((s, p) => s + p.tokens, 0); }
