import { appendFileSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from 'node:path';
import {
  ensureRunsDir,
  readCurrentSession,
  writeCurrentSession,
  clearCurrentSession,
  updateIndexEntry,
  findInProgressSessions,
  readIndex,
  type IndexEntry,
} from './runs-dir.js';

export interface SessionJson {
  session_id: string;
  task: string;
  start_time: string;
  end_time?: string;
  status: 'in_progress' | 'completed';
  expected_record_types?: string[];
  total_records?: number;
}

export function generateSessionId(): string {
  const now = new Date();
  const y = now.getFullYear();
  const m = String(now.getMonth() + 1).padStart(2, '0');
  const d = String(now.getDate()).padStart(2, '0');
  const h = String(now.getHours()).padStart(2, '0');
  const min = String(now.getMinutes()).padStart(2, '0');
  return `adhoc_${y}${m}${d}_${h}${min}`;
}

export function isoNow(): string {
  return new Date().toISOString();
}

export function createSession(
  task: string,
  sessionId?: string,
  projectRoot?: string,
): string {
  const sid = sessionId || generateSessionId();
  const runsDir = ensureRunsDir(projectRoot);
  const sessionDir = join(runsDir, sid);
  mkdirSync(sessionDir, { recursive: true });

  const session: SessionJson = {
    session_id: sid,
    task,
    start_time: isoNow(),
    status: 'in_progress',
    expected_record_types: ['data', 'change', 'conversation'],
  };

  writeFileSync(join(sessionDir, 'session.json'), JSON.stringify(session, null, 2), 'utf-8');
  writeCurrentSession(sid, projectRoot);

  updateIndexEntry({
    id: sid,
    type: 'adhoc',
    status: 'in_progress',
    task,
    created: session.start_time,
    last_updated: session.start_time,
  }, projectRoot);

  return sid;
}

export function getSessionDir(sessionId: string, projectRoot?: string): string {
  return join(ensureRunsDir(projectRoot), sessionId);
}

export function getActiveSession(projectRoot?: string): SessionJson | null {
  const sid = readCurrentSession(projectRoot);
  if (!sid) return null;
  return readSession(sid, projectRoot);
}

export function readSession(sessionId: string, projectRoot?: string): SessionJson | null {
  const path = join(getSessionDir(sessionId, projectRoot), 'session.json');
  try {
    return JSON.parse(readFileSync(path, 'utf-8')) as SessionJson;
  } catch {
    return null;
  }
}

export function updateSession(
  sessionId: string,
  updates: Partial<SessionJson>,
  projectRoot?: string,
): void {
  const session = readSession(sessionId, projectRoot) || { session_id: sessionId, task: '', start_time: isoNow(), status: 'in_progress' as const };
  Object.assign(session, updates);
  writeFileSync(
    join(getSessionDir(sessionId, projectRoot), 'session.json'),
    JSON.stringify(session, null, 2),
    'utf-8',
  );
}

export function endSession(sessionId: string, projectRoot?: string): void {
  updateSession(sessionId, { status: 'completed', end_time: isoNow() }, projectRoot);
  updateIndexEntry({ id: sessionId, type: 'adhoc', status: 'completed', last_updated: isoNow() }, projectRoot);
  clearCurrentSession(projectRoot);
}

export function appendToTrail(sessionId: string, records: Record<string, unknown>[], projectRoot?: string): void {
  const trailPath = join(getSessionDir(sessionId, projectRoot), 'audit_trail.jsonl');
  const lines = records.map(r => JSON.stringify(r)).join('\n') + '\n';
  appendFileSync(trailPath, lines, 'utf-8');
}

export function readTrail(sessionId: string, projectRoot?: string): Record<string, unknown>[] {
  const trailPath = join(getSessionDir(sessionId, projectRoot), 'audit_trail.jsonl');
  try {
    const content = readFileSync(trailPath, 'utf-8').trim();
    if (!content) return [];
    return content.split('\n').filter(Boolean).map(line => JSON.parse(line) as Record<string, unknown>);
  } catch {
    return [];
  }
}

export interface RecoverySummary {
  sessionId: string;
  task: string;
  recentActivity: IndexEntry[];
  userCorrections: Record<string, unknown>[];
  unresolvedIssues: string[];
  recommendedPriorities: string[];
  level: number;
}

export function recoverContext(
  sessionId: string,
  level: number,
  projectRoot?: string,
): RecoverySummary {
  const session = readSession(sessionId, projectRoot);
  const idx = readIndex(projectRoot);
  const recentActivity = idx.entries.slice(-5);
  const trail = readTrail(sessionId, projectRoot);
  const userCorrections = trail.filter(r => r['action_type'] === 'user_correction');

  const summary: RecoverySummary = {
    sessionId,
    task: session?.task || '(unknown)',
    recentActivity,
    userCorrections,
    unresolvedIssues: [],
    recommendedPriorities: [],
    level,
  };

  if (level >= 1) {
    const last = trail.slice(-3);
    if (last.length > 0) {
      summary.recommendedPriorities.push(`Last action: ${JSON.stringify(last[last.length - 1]?.['action'] || 'none')}`);
    }
  }

  if (level >= 3) {
    summary.recommendedPriorities.push(`Full trail: ${trail.length} records`);
  }

  let checkCount = 0;
  for (const entry of recentActivity) {
    if (entry.status === 'in_progress' && entry.id !== sessionId) {
      summary.unresolvedIssues.push(`Unfinished session: ${entry.id} (${entry.task || 'no task'})`);
      checkCount++;
      if (checkCount >= 3) break;
    }
  }

  return summary;
}

export function checkUnfinishedSessions(projectRoot?: string): IndexEntry[] {
  return findInProgressSessions(projectRoot);
}

export function generateSessionSummary(sessionId: string, projectRoot?: string): string {
  const session = readSession(sessionId, projectRoot);
  const trail = readTrail(sessionId, projectRoot);
  const corrections = trail.filter(r => r['action_type'] === 'user_correction');
  const changes = trail.filter(r => r['action'] === 'edit_file' || r['action'] === 'create_file' || r['action'] === 'delete_file');

  const lines: string[] = [
    `# Session Summary | ${sessionId}`,
    '',
    `## Task: ${session?.task || '(unknown)'}`,
    `## Time: ${session?.start_time || '?'} → ${session?.end_time || 'in_progress'}`,
    `## Status: ${session?.status || 'unknown'}`,
    '',
    '## Completed Work',
  ];

  for (const r of trail) {
    if (r['action']) {
      lines.push(`- ${r['action']}: ${r['detail'] || r['reason'] || '(no detail)'}`);
    }
  }

  if (corrections.length > 0) {
    lines.push('', '## User Corrections');
    for (const c of corrections) {
      lines.push(`- Original: ${c['original_claim']}`);
      lines.push(`  Correction: ${c['correction']}`);
      if (c['principle_extracted']) {
        lines.push(`  Principle: ${c['principle_extracted']}`);
      }
    }
  }

  if (changes.length > 0) {
    lines.push('', '## Files Changed');
    const fileSet = new Set<string>();
    for (const c of changes) {
      const files = c['files'];
      if (Array.isArray(files)) {
        for (const f of files) fileSet.add(String(f));
      }
    }
    for (const f of fileSet) lines.push(`- ${f}`);
  }

  lines.push('', '## Stats');
  lines.push(`- Total records: ${trail.length}`);
  lines.push(`- Corrections: ${corrections.length}`);
  lines.push(`- File changes: ${changes.length}`);

  return lines.join('\n');
}
