import { join, resolve } from 'node:path';
import { mkdirSync } from 'node:fs';
import { homedir } from 'node:os';

export const DATA_PATH = process.env.DATA_PATH ?? join(process.cwd(), 'data');

// Unified, file-based store for all agent items, living outside the repo. Every skill/tool/task/
// process/extension is a directory under one of these type subfolders — no scope tiers, no DB.
export const OFFICER_ITEMS_DIR = process.env.OFFICER_ITEMS_DIR ?? join(process.cwd(), 'officer-items');

export type ItemType = 'skills' | 'tools' | 'tasks' | 'processes' | 'extensions' | 'agents';

export const ITEM_TYPES: ItemType[] = ['skills', 'tools', 'tasks', 'processes', 'extensions', 'agents'];

export const itemsDir = (type: ItemType) => join(OFFICER_ITEMS_DIR, type);

export const ensureItemDirs = () => {
  for (const type of ITEM_TYPES) mkdirSync(itemsDir(type), { recursive: true });
};

export const SERVER_CONFIG_DIR = join(DATA_PATH, 'server-settings');

// Every run of a given agent shares one working directory. That is deliberate and load-bearing: the
// `claude` CLI groups transcripts by cwd (see api/chat/claude-sessions.ts), so a shared cwd is what
// makes an agent's runs show up as their own project group in /chat, listed newest-first, with no
// database row anywhere. The accumulated CLAUDE.md / LEARNINGS.md for the agent live here too.
export const getAgentRunsDir = (dirName: string) => join(DATA_PATH, 'agentic_runs', dirName);

// The `pi`/opencode agent's own config dir (auth.json + models.json). External-tool path.
export const AGENT_CONFIG_DIR = join(homedir(), '.pi', 'agent');

export const SEED_PATH = resolve(import.meta.dir, '../../seed');

// The managed home under DATA_PATH. A remnant of the first architecture, where every user ran inside
// their own Docker container and this was that container's home — seeded by provisioning, described to
// the agent by a generated CLAUDE.md. Both of those are gone, and nothing executes here any more:
// terminals, chats and task runs all use getOwnerHomeDir below. It survives only as that function's
// fallback for when HOME_DIR is unset, and in pipeline-executor.
export const getHomeDir = (email: string) => join(DATA_PATH, email, 'home');

// Where the owner's sessions actually run: their real login home when HOME_DIR is set, so platform
// terminals/chats/tasks share config and credentials with the shell they use outside Officer.
export const getOwnerHomeDir = (email: string): string => process.env.HOME_DIR ?? getHomeDir(email);


export const getTmpAttachmentsDir = (email: string) => join(DATA_PATH, email, 'attachments', 'tmp');

export const getAttachmentsDir = (email: string, sessionId: string) => join(DATA_PATH, email, 'attachments', sessionId);

// Per-account email storage: DATA_PATH/<owner>/email_accounts/<accountEmail>/emails.db, with a
// single attachment_cache/ shared across the owner's accounts.
export const getEmailAccountsDir = (ownerEmail: string) => join(DATA_PATH, ownerEmail, 'email_accounts');
export const getEmailDbPath = (ownerEmail: string, accountEmail: string) =>
  join(getEmailAccountsDir(ownerEmail), accountEmail, 'emails.db');
export const getEmailAttachmentCacheDir = (ownerEmail: string) =>
  join(getEmailAccountsDir(ownerEmail), 'attachment_cache');

// Sanitises a display username or email into a bare, lowercase, shell-safe token. The name and the
// 32-char Linux limit are the last trace of the per-container architecture, where this really did name
// a Linux user inside the user's container. Nothing creates a Linux user now — the value is carried
// through the websocket/job payloads and ends up only as a claim inside the signed task token, so this
// is a sanitiser rather than an account name. Left in place because unpicking it means changing what
// goes into that token and into WSData, which is a wider change than a cleanup.
export const toShellUsername = (username: string, email: string): string => {
  const raw = username || email.split('@')[0]!;
  // Replace invalid chars, lowercase, truncate to 32 chars
  return (
    raw
      .replace(/@.*$/, '')
      .replace(/[^a-zA-Z0-9._-]/g, '_')
      .toLowerCase()
      .slice(0, 32) || 'officer'
  );
};
