/**
 * Team Routes - REST API for team message visualization & management
 *
 * Directory Structure (NEW - session-bound):
 * .workflow/.team/
 * ├── TLS-demo-2026-02-15/      # session-id (root)
 * │   ├── .msg/                 # messages (session-level)
 * │   │   ├── meta.json
 * │   │   └── messages.jsonl
 * │   ├── spec/                 # artifacts (siblings of .msg)
 * │   └── plan/
 *
 * Legacy Support: Also scans .workflow/.team-msg/{team-name}/
 *
 * Endpoints:
 * - GET    /api/teams                       - List all teams (with ?location filter)
 * - GET    /api/teams/:name/messages        - Get messages (with filters)
 * - GET    /api/teams/:name/status          - Get member status summary
 * - GET    /api/teams/:name/artifacts       - Get artifacts tree structure
 * - GET    /api/teams/:name/artifacts/*path - Get artifact file content
 * - POST   /api/teams/:name/archive         - Archive a team
 * - POST   /api/teams/:name/unarchive       - Unarchive a team
 * - DELETE /api/teams/:name                 - Delete a team
 */

import { existsSync, readdirSync, rmSync, statSync, readFileSync } from 'fs';
import { join, extname } from 'path';
import type { RouteContext } from './types.js';
import { readAllMessages, getLogDir, getEffectiveTeamMeta, readTeamMeta, writeTeamMeta } from '../../tools/team-msg.js';
import type { TeamMeta } from '../../tools/team-msg.js';
import { getProjectRoot } from '../../utils/path-validator.js';

/**
 * Artifact node structure for tree representation
 */
interface ArtifactNode {
  type: 'file' | 'directory';
  name: string;
  path: string;           // Relative to session directory
  contentType: 'markdown' | 'json' | 'text' | 'unknown';
  size?: number;          // File size (bytes)
  modifiedAt?: string;    // Last modified time
  children?: ArtifactNode[];  // Directory children
}

/**
 * Detect content type from file extension
 */
function detectContentType(fileName: string): ArtifactNode['contentType'] {
  const ext = extname(fileName).toLowerCase();
  if (['.md', '.markdown'].includes(ext)) return 'markdown';
  if (['.json'].includes(ext)) return 'json';
  if (['.txt', '.log', '.tsv', '.csv'].includes(ext)) return 'text';
  return 'unknown';
}

/**
 * Recursively scan artifacts directory
 * Skips .msg directory (message storage)
 */
function scanArtifactsDirectory(dirPath: string, basePath: string): ArtifactNode[] {
  const nodes: ArtifactNode[] = [];

  if (!existsSync(dirPath)) {
    return nodes;
  }

  try {
    const entries = readdirSync(dirPath, { withFileTypes: true });

    for (const entry of entries) {
      // Skip .msg directory - that's for messages, not artifacts
      if (entry.name === '.msg') continue;

      const fullPath = join(dirPath, entry.name);
      const relativePath = join(basePath, entry.name).replace(/\\/g, '/');

      if (entry.isDirectory()) {
        const children = scanArtifactsDirectory(fullPath, relativePath);
        const stat = statSync(fullPath);

        nodes.push({
          type: 'directory',
          name: entry.name,
          path: relativePath,
          contentType: 'unknown',
          modifiedAt: stat.mtime.toISOString(),
          children,
        });
      } else if (entry.isFile()) {
        const stat = statSync(fullPath);

        nodes.push({
          type: 'file',
          name: entry.name,
          path: relativePath,
          contentType: detectContentType(entry.name),
          size: stat.size,
          modifiedAt: stat.mtime.toISOString(),
        });
      }
    }

    // Sort: directories first, then files, both alphabetically
    nodes.sort((a, b) => {
      if (a.type !== b.type) {
        return a.type === 'directory' ? -1 : 1;
      }
      return a.name.localeCompare(b.name);
    });
  } catch (e) {
    // Ignore errors (permission, etc.)
  }

  return nodes;
}

/**
 * Get session directory (artifacts are siblings of .msg/)
 * NEW: .workflow/.team/{session-id}/
 */
function getSessionDir(sessionId: string, root: string): string {
  return join(root, '.workflow', '.team', sessionId);
}

/**
 * Get legacy team directory
 * OLD: .workflow/.team-msg/{team-name}/
 */
function getLegacyTeamDir(teamName: string, root: string): string {
  return join(root, '.workflow', '.team-msg', teamName);
}

/**
 * List all sessions from new .team/ directory
 * Each subdirectory with .msg/ folder is a valid session
 */
function listSessions(root: string): Array<{ sessionId: string; path: string }> {
  const teamDir = join(root, '.workflow', '.team');
  const sessions: Array<{ sessionId: string; path: string }> = [];

  console.log('[team-routes] listSessions - root:', root);
  console.log('[team-routes] listSessions - teamDir:', teamDir);
  console.log('[team-routes] listSessions - existsSync(teamDir):', existsSync(teamDir));

  if (!existsSync(teamDir)) {
    return sessions;
  }

  try {
    const entries = readdirSync(teamDir, { withFileTypes: true });
    console.log('[team-routes] listSessions - entries:', entries.map(e => e.name));
    for (const entry of entries) {
      if (entry.isDirectory()) {
        const msgDir = join(teamDir, entry.name, '.msg');
        console.log('[team-routes] listSessions - checking msgDir:', msgDir, 'exists:', existsSync(msgDir));
        if (existsSync(msgDir)) {
          sessions.push({ sessionId: entry.name, path: join(teamDir, entry.name) });
        }
      }
    }
  } catch (err) {
    console.error('[team-routes] listSessions error:', err);
  }

  console.log('[team-routes] listSessions - found sessions:', sessions.length);
  return sessions;
}

/**
 * List teams from old .team-msg/ directory (backward compatibility)
 */
function listLegacyTeams(root: string): Array<{ teamName: string; path: string }> {
  const teamMsgDir = join(root, '.workflow', '.team-msg');
  const teams: Array<{ teamName: string; path: string }> = [];

  if (!existsSync(teamMsgDir)) {
    return teams;
  }

  try {
    const entries = readdirSync(teamMsgDir, { withFileTypes: true });
    for (const entry of entries) {
      if (entry.isDirectory()) {
        teams.push({ teamName: entry.name, path: join(teamMsgDir, entry.name) });
      }
    }
  } catch {
    // Ignore errors
  }

  return teams;
}

function jsonResponse(res: import('http').ServerResponse, status: number, data: unknown): void {
  res.writeHead(status, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify(data));
}

/**
 * Resolve project root from context
 * Priority: initialPath (from server startup) > getProjectRoot()
 */
function resolveProjectRoot(ctx: RouteContext): string {
  return ctx.initialPath || getProjectRoot();
}

export async function handleTeamRoutes(ctx: RouteContext): Promise<boolean> {
  const { pathname, req, res, url, handlePostRequest } = ctx;

  if (!pathname.startsWith('/api/teams')) return false;

  // ====== GET /api/teams/debug - Debug endpoint ======
  if (pathname === '/api/teams/debug' && req.method === 'GET') {
    const root = resolveProjectRoot(ctx);
    const teamDir = join(root, '.workflow', '.team');
    const legacyDir = join(root, '.workflow', '.team-msg');

    const debug = {
      projectRoot: root,
      teamDir,
      legacyDir,
      teamDirExists: existsSync(teamDir),
      legacyDirExists: existsSync(legacyDir),
      teamDirContents: [] as string[],
      sessionMsgDirs: [] as { session: string; msgExists: boolean }[],
    };

    if (existsSync(teamDir)) {
      try {
        const entries = readdirSync(teamDir, { withFileTypes: true });
        debug.teamDirContents = entries.map(e => `${e.name} (${e.isDirectory() ? 'dir' : 'file'})`);
        for (const entry of entries) {
          if (entry.isDirectory()) {
            const msgDir = join(teamDir, entry.name, '.msg');
            debug.sessionMsgDirs.push({
              session: entry.name,
              msgExists: existsSync(msgDir),
            });
          }
        }
      } catch (err) {
        (debug as any).error = String(err);
      }
    }

    jsonResponse(res, 200, debug);
    return true;
  }

  // ====== GET /api/teams - List all teams ======
  if (pathname === '/api/teams' && req.method === 'GET') {
    try {
      const root = resolveProjectRoot(ctx);
      const locationFilter = url.searchParams.get('location') || 'active';

      // Collect from new session-bound structure
      const sessions = listSessions(root);
      // Collect from legacy structure
      const legacyTeams = listLegacyTeams(root);

      // Build unified team list
      const teams: Array<{
        name: string;
        messageCount: number;
        lastActivity: string;
        status: string;
        created_at: string;
        updated_at: string;
        archived_at?: string;
        pipeline_mode?: string;
        pipeline_stages?: string[];
        role_state?: Record<string, Record<string, unknown>>;
        roles?: string[];
        team_name?: string;
        memberCount: number;
        members: string[];
        isLegacy: boolean;
      }> = [];

      // Process new sessions
      for (const session of sessions) {
        const messages = readAllMessages(session.sessionId);
        const lastMsg = messages[messages.length - 1];
        const meta = getEffectiveTeamMeta(session.sessionId);

        const memberSet = new Set<string>();
        for (const msg of messages) {
          memberSet.add(msg.from);
          memberSet.add(msg.to);
        }

        teams.push({
          name: session.sessionId,
          messageCount: messages.length,
          lastActivity: lastMsg?.ts || '',
          status: meta.status,
          created_at: meta.created_at,
          updated_at: meta.updated_at,
          archived_at: meta.archived_at,
          pipeline_mode: meta.pipeline_mode,
          pipeline_stages: meta.pipeline_stages,
          role_state: meta.role_state,
          roles: meta.roles,
          team_name: meta.team_name,
          memberCount: memberSet.size,
          members: Array.from(memberSet),
          isLegacy: false,
        });
      }

      // Process legacy teams
      for (const team of legacyTeams) {
        // Skip if already found in new structure (same name)
        if (teams.some(t => t.name === team.teamName)) continue;

        const messages = readAllMessages(team.teamName);
        const lastMsg = messages[messages.length - 1];
        const meta = getEffectiveTeamMeta(team.teamName);

        const memberSet = new Set<string>();
        for (const msg of messages) {
          memberSet.add(msg.from);
          memberSet.add(msg.to);
        }

        teams.push({
          name: team.teamName,
          messageCount: messages.length,
          lastActivity: lastMsg?.ts || '',
          status: meta.status,
          created_at: meta.created_at,
          updated_at: meta.updated_at,
          archived_at: meta.archived_at,
          pipeline_mode: meta.pipeline_mode,
          pipeline_stages: meta.pipeline_stages,
          role_state: meta.role_state,
          roles: meta.roles,
          team_name: meta.team_name,
          memberCount: memberSet.size,
          members: Array.from(memberSet),
          isLegacy: true,
        });
      }

      // Apply filters
      const filteredTeams = teams
        .filter(t => {
          if (locationFilter === 'all') return true;
          if (locationFilter === 'archived') return t.status === 'archived';
          return t.status !== 'archived';
        })
        .sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));

      jsonResponse(res, 200, { teams: filteredTeams });
      return true;
    } catch (error) {
      jsonResponse(res, 500, { error: (error as Error).message });
      return true;
    }
  }

  // ====== POST /api/teams/:name/archive ======
  const archiveMatch = pathname.match(/^\/api\/teams\/([^/]+)\/archive$/);
  if (archiveMatch && req.method === 'POST') {
    const teamName = decodeURIComponent(archiveMatch[1]);
    handlePostRequest(req, res, async () => {
      const dir = getLogDir(teamName);
      if (!existsSync(dir)) {
        throw new Error(`Team "${teamName}" not found`);
      }
      const meta = getEffectiveTeamMeta(teamName);
      meta.status = 'archived';
      meta.archived_at = new Date().toISOString();
      meta.updated_at = new Date().toISOString();
      writeTeamMeta(teamName, meta);
      return { success: true, team: teamName, status: 'archived' };
    });
    return true;
  }

  // ====== POST /api/teams/:name/unarchive ======
  const unarchiveMatch = pathname.match(/^\/api\/teams\/([^/]+)\/unarchive$/);
  if (unarchiveMatch && req.method === 'POST') {
    const teamName = decodeURIComponent(unarchiveMatch[1]);
    handlePostRequest(req, res, async () => {
      const dir = getLogDir(teamName);
      if (!existsSync(dir)) {
        throw new Error(`Team "${teamName}" not found`);
      }
      const meta = getEffectiveTeamMeta(teamName);
      meta.status = 'active';
      delete meta.archived_at;
      meta.updated_at = new Date().toISOString();
      writeTeamMeta(teamName, meta);
      return { success: true, team: teamName, status: 'active' };
    });
    return true;
  }

  // ====== DELETE /api/teams/:name ======
  const deleteMatch = pathname.match(/^\/api\/teams\/([^/]+)$/);
  if (deleteMatch && req.method === 'DELETE') {
    const teamName = decodeURIComponent(deleteMatch[1]);
    const root = resolveProjectRoot(ctx);
    try {
      // Try new session-bound location first
      const sessionDir = getSessionDir(teamName, root);
      if (existsSync(sessionDir)) {
        rmSync(sessionDir, { recursive: true, force: true });
        jsonResponse(res, 200, { success: true, team: teamName, deleted: true });
        return true;
      }

      // Fallback to legacy location
      const legacyDir = getLegacyTeamDir(teamName, root);
      if (existsSync(legacyDir)) {
        rmSync(legacyDir, { recursive: true, force: true });
        jsonResponse(res, 200, { success: true, team: teamName, deleted: true });
        return true;
      }

      jsonResponse(res, 404, { error: `Team "${teamName}" not found` });
      return true;
    } catch (error) {
      jsonResponse(res, 500, { error: (error as Error).message });
      return true;
    }
  }

  // ====== GET requests only from here ======
  if (req.method !== 'GET') return false;

  // ====== GET /api/teams/:name/artifacts or /api/teams/:name/artifacts/*path ======
  const artifactsMatch = pathname.match(/^\/api\/teams\/([^/]+)\/artifacts(?:\/(.*))?$/);
  if (artifactsMatch) {
    const artifactsTeamName = decodeURIComponent(artifactsMatch[1]);
    const artifactPath = artifactsMatch[2] ? decodeURIComponent(artifactsMatch[2]) : null;
    const root = resolveProjectRoot(ctx);

    try {
      // NEW: Session directory contains both .msg/ and artifacts
      // The team name IS the session ID now
      const sessionDir = getSessionDir(artifactsTeamName, root);

      if (!existsSync(sessionDir)) {
        // Check if it's a legacy team with session_id in meta
        const meta = getEffectiveTeamMeta(artifactsTeamName);
        const legacySessionId = (meta as unknown as Record<string, unknown>).session_id as string | undefined;
        if (legacySessionId) {
          // Legacy team with session_id - redirect to session directory
          const legacySessionDir = getSessionDir(legacySessionId, root);
          if (existsSync(legacySessionDir)) {
            serveArtifacts(legacySessionDir, legacySessionId, meta, artifactPath, res);
            return true;
          }
        }

        jsonResponse(res, 200, {
          tree: [],
          sessionId: null,
          message: 'Session directory not found'
        });
        return true;
      }

      // Direct session access - artifacts are siblings of .msg/
      const meta = getEffectiveTeamMeta(artifactsTeamName);
      serveArtifacts(sessionDir, artifactsTeamName, meta, artifactPath, res);
      return true;
    } catch (error) {
      jsonResponse(res, 500, { error: (error as Error).message });
      return true;
    }
  }

  // ====== GET /api/teams/:name/messages or /api/teams/:name/status ======
  const match = pathname.match(/^\/api\/teams\/([^/]+)\/(messages|status)$/);
  if (!match) return false;

  const teamName = decodeURIComponent(match[1]);
  const action = match[2];

  // GET /api/teams/:name/messages
  if (action === 'messages') {
    try {
      let messages = readAllMessages(teamName);

      // Apply query filters
      const fromFilter = url.searchParams.get('from');
      const toFilter = url.searchParams.get('to');
      const typeFilter = url.searchParams.get('type');
      const last = parseInt(url.searchParams.get('last') || '50', 10);
      const offset = parseInt(url.searchParams.get('offset') || '0', 10);

      if (fromFilter) messages = messages.filter(m => m.from === fromFilter);
      if (toFilter) messages = messages.filter(m => m.to === toFilter);
      if (typeFilter) messages = messages.filter(m => m.type === typeFilter);

      const total = messages.length;
      const sliced = messages.slice(Math.max(0, total - last - offset), total - offset);

      jsonResponse(res, 200, { total, showing: sliced.length, messages: sliced });
      return true;
    } catch (error) {
      jsonResponse(res, 500, { error: (error as Error).message });
      return true;
    }
  }

  // GET /api/teams/:name/status
  if (action === 'status') {
    try {
      const messages = readAllMessages(teamName);

      const memberMap = new Map<string, { member: string; lastSeen: string; lastAction: string; messageCount: number }>();

      for (const msg of messages) {
        for (const role of [msg.from, msg.to]) {
          if (!memberMap.has(role)) {
            memberMap.set(role, { member: role, lastSeen: msg.ts, lastAction: '', messageCount: 0 });
          }
        }
        const entry = memberMap.get(msg.from)!;
        entry.lastSeen = msg.ts;
        entry.lastAction = `sent ${msg.type} -> ${msg.to}`;
        entry.messageCount++;
      }

      const members = Array.from(memberMap.values()).sort((a, b) => b.lastSeen.localeCompare(a.lastSeen));

      jsonResponse(res, 200, { members, total_messages: messages.length });
      return true;
    } catch (error) {
      jsonResponse(res, 500, { error: (error as Error).message });
      return true;
    }
  }

  return false;
}

/**
 * Serve artifacts from session directory
 */
function serveArtifacts(
  sessionDir: string,
  sessionId: string,
  meta: TeamMeta,
  artifactPath: string | null,
  res: import('http').ServerResponse
): void {
  // If specific file path requested
  if (artifactPath) {
    const filePath = join(sessionDir, artifactPath);

    if (!existsSync(filePath)) {
      jsonResponse(res, 404, {
        error: 'Artifact not found',
        path: artifactPath
      });
      return;
    }

    const stat = statSync(filePath);

    if (stat.isDirectory()) {
      // Return directory listing
      const children = scanArtifactsDirectory(filePath, artifactPath);
      jsonResponse(res, 200, {
        type: 'directory',
        name: artifactPath.split('/').pop() || '',
        path: artifactPath,
        children,
        modifiedAt: stat.mtime.toISOString()
      });
      return;
    }

    // Return file content
    const content = readFileSync(filePath, 'utf-8');
    const contentType = detectContentType(artifactPath.split('/').pop() || '');

    jsonResponse(res, 200, {
      type: 'file',
      name: artifactPath.split('/').pop() || '',
      path: artifactPath,
      contentType,
      size: stat.size,
      modifiedAt: stat.mtime.toISOString(),
      content
    });
    return;
  }

  // Return full artifacts tree
  const tree = scanArtifactsDirectory(sessionDir, '');

  jsonResponse(res, 200, {
    teamName: sessionId,
    sessionId: sessionId,
    sessionPath: sessionDir,
    pipelineMode: meta.pipeline_mode,
    tree,
    totalFiles: countFiles(tree),
    totalDirectories: countDirectories(tree),
    totalSize: countTotalSize(tree)
  });
}

/**
 * Count total files in artifact tree
 */
function countFiles(nodes: ArtifactNode[]): number {
  let count = 0;
  for (const node of nodes) {
    if (node.type === 'file') {
      count++;
    } else if (node.children) {
      count += countFiles(node.children);
    }
  }
  return count;
}

/**
 * Count total directories in artifact tree
 */
function countDirectories(nodes: ArtifactNode[]): number {
  let count = 0;
  for (const node of nodes) {
    if (node.type === 'directory') {
      count++;
      if (node.children) {
        count += countDirectories(node.children);
      }
    }
  }
  return count;
}

/**
 * Count total size of all files in artifact tree
 */
function countTotalSize(nodes: ArtifactNode[]): number {
  let totalSize = 0;
  for (const node of nodes) {
    if (node.type === 'file' && node.size) {
      totalSize += node.size;
    } else if (node.children) {
      totalSize += countTotalSize(node.children);
    }
  }
  return totalSize;
}
