import type { Command } from 'commander';
import { withAuth } from './with-auth.js';
import { selectItem } from './select-dialog.js';
import {
  fetchMissions,
  fetchMission,
  createMission,
  updateMission,
  fetchMissionTasks,
  createMissionTask,
  updateMissionTask,
  fetchProjects,
} from '../tui/gateway-api.js';
import type { MissionInfo, MissionTaskInfo } from '../tui/gateway-api.js';

function formatMission(m: MissionInfo): string {
  return `${m.name} — ${m.status}${m.phase ? ` (${m.phase})` : ''}`;
}

function showMissionDetail(m: MissionInfo) {
  console.log(`  ID:          ${m.id}`);
  console.log(`  Name:        ${m.name}`);
  console.log(`  Status:      ${m.status}`);
  console.log(`  Phase:       ${m.phase ?? '—'}`);
  console.log(`  Project:     ${m.projectId ?? '—'}`);
  console.log(`  Description: ${m.description ?? '—'}`);
  console.log(`  Created:     ${new Date(m.createdAt).toLocaleString()}`);
}

function showTaskDetail(t: MissionTaskInfo) {
  console.log(`  ID:          ${t.id}`);
  console.log(`  Status:      ${t.status}`);
  console.log(`  Description: ${t.description ?? '—'}`);
  console.log(`  Notes:       ${t.notes ?? '—'}`);
  console.log(`  PR:          ${t.pr ?? '—'}`);
  console.log(`  Created:     ${new Date(t.createdAt).toLocaleString()}`);
}

export function registerMissionCommand(program: Command) {
  const cmd = program
    .command('mission')
    .description('Manage missions')
    .option('-g, --gateway <url>', 'Gateway URL', 'http://localhost:14242')
    .option('--list', 'List all missions')
    .option('--init', 'Create a new mission')
    .option('--plan <idOrName>', 'Run PRD wizard for a mission')
    .option('--update <idOrName>', 'Update a mission')
    .option('--project <idOrName>', 'Scope to project')
    .argument('[id]', 'Show mission detail by ID')
    .configureHelp({ sortSubcommands: true })
    .action(
      async (
        id: string | undefined,
        opts: {
          gateway: string;
          list?: boolean;
          init?: boolean;
          plan?: string;
          update?: string;
          project?: string;
        },
      ) => {
        const auth = await withAuth(opts.gateway);

        if (opts.list) {
          return listMissions(auth.gateway, auth.cookie);
        }
        if (opts.init) {
          return initMission(auth.gateway, auth.cookie);
        }
        if (opts.plan) {
          return planMission(auth.gateway, auth.cookie, opts.plan, opts.project);
        }
        if (opts.update) {
          return updateMissionWizard(auth.gateway, auth.cookie, opts.update);
        }
        if (id) {
          return showMission(auth.gateway, auth.cookie, id);
        }

        // Default: interactive select
        return interactiveSelect(auth.gateway, auth.cookie);
      },
    );

  // Task subcommand
  cmd
    .command('task')
    .description('Manage mission tasks')
    .option('-g, --gateway <url>', 'Gateway URL', 'http://localhost:14242')
    .option('--list', 'List tasks for a mission')
    .option('--new', 'Create a task')
    .option('--update <taskId>', 'Update a task')
    .option('--mission <idOrName>', 'Mission ID or name')
    .argument('[taskId]', 'Show task detail')
    .action(
      async (
        taskId: string | undefined,
        taskOpts: {
          gateway: string;
          list?: boolean;
          new?: boolean;
          update?: string;
          mission?: string;
        },
      ) => {
        const auth = await withAuth(taskOpts.gateway);

        const missionId = await resolveMissionId(auth.gateway, auth.cookie, taskOpts.mission);
        if (!missionId) return;

        if (taskOpts.list) {
          return listTasks(auth.gateway, auth.cookie, missionId);
        }
        if (taskOpts.new) {
          return createTaskWizard(auth.gateway, auth.cookie, missionId);
        }
        if (taskOpts.update) {
          return updateTaskWizard(auth.gateway, auth.cookie, missionId, taskOpts.update);
        }
        if (taskId) {
          return showTask(auth.gateway, auth.cookie, missionId, taskId);
        }

        return listTasks(auth.gateway, auth.cookie, missionId);
      },
    );

  return cmd;
}

async function resolveMissionByName(
  gateway: string,
  cookie: string,
  idOrName: string,
): Promise<MissionInfo | undefined> {
  const missions = await fetchMissions(gateway, cookie);
  return missions.find((m) => m.id === idOrName || m.name === idOrName);
}

async function resolveMissionId(
  gateway: string,
  cookie: string,
  idOrName?: string,
): Promise<string | undefined> {
  if (idOrName) {
    const mission = await resolveMissionByName(gateway, cookie, idOrName);
    if (!mission) {
      console.error(`Mission "${idOrName}" not found.`);
      return undefined;
    }
    return mission.id;
  }

  // Interactive select
  const missions = await fetchMissions(gateway, cookie);
  const selected = await selectItem(missions, {
    message: 'Select a mission:',
    render: formatMission,
    emptyMessage: 'No missions found. Create one with `mosaic mission --init`.',
  });
  return selected?.id;
}

async function listMissions(gateway: string, cookie: string) {
  const missions = await fetchMissions(gateway, cookie);
  if (missions.length === 0) {
    console.log('No missions found.');
    return;
  }
  console.log(`Missions (${missions.length}):\n`);
  for (const m of missions) {
    const phase = m.phase ? ` [${m.phase}]` : '';
    console.log(`  ${m.name}  ${m.status}${phase}  ${m.id.slice(0, 8)}`);
  }
}

async function showMission(gateway: string, cookie: string, id: string) {
  try {
    const mission = await fetchMission(gateway, cookie, id);
    showMissionDetail(mission);
  } catch {
    // Try resolving by name
    const m = await resolveMissionByName(gateway, cookie, id);
    if (!m) {
      console.error(`Mission "${id}" not found.`);
      process.exit(1);
    }
    showMissionDetail(m);
  }
}

async function interactiveSelect(gateway: string, cookie: string) {
  const missions = await fetchMissions(gateway, cookie);
  const selected = await selectItem(missions, {
    message: 'Select a mission:',
    render: formatMission,
    emptyMessage: 'No missions found. Create one with `mosaic mission --init`.',
  });
  if (selected) {
    showMissionDetail(selected);
  }
}

async function initMission(gateway: string, cookie: string) {
  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    const name = await ask('Mission name: ');
    if (!name.trim()) {
      console.error('Name is required.');
      return;
    }

    // Project selection
    const projects = await fetchProjects(gateway, cookie);
    let projectId: string | undefined;
    if (projects.length > 0) {
      const selected = await selectItem(projects, {
        message: 'Assign to project (required):',
        render: (p) => `${p.name} (${p.status})`,
        emptyMessage: 'No projects found.',
      });
      if (selected) projectId = selected.id;
    }

    const description = await ask('Description (optional): ');

    const mission = await createMission(gateway, cookie, {
      name: name.trim(),
      projectId,
      description: description.trim() || undefined,
      status: 'planning',
    });

    console.log(`\nMission "${mission.name}" created (${mission.id}).`);
  } finally {
    rl.close();
  }
}

async function planMission(
  gateway: string,
  cookie: string,
  idOrName: string,
  _projectIdOrName?: string,
) {
  const mission = await resolveMissionByName(gateway, cookie, idOrName);
  if (!mission) {
    console.error(`Mission "${idOrName}" not found.`);
    process.exit(1);
  }

  console.log(`Planning mission: ${mission.name}\n`);

  try {
    const { runPrdWizard } = await import('@mosaicstack/prdy');
    await runPrdWizard({
      name: mission.name,
      projectPath: process.cwd(),
      interactive: true,
    });
  } catch (err) {
    console.error(`PRD wizard failed: ${err instanceof Error ? err.message : String(err)}`);
    process.exit(1);
  }
}

async function updateMissionWizard(gateway: string, cookie: string, idOrName: string) {
  const mission = await resolveMissionByName(gateway, cookie, idOrName);
  if (!mission) {
    console.error(`Mission "${idOrName}" not found.`);
    process.exit(1);
  }

  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    console.log(`Updating mission: ${mission.name}\n`);

    const name = await ask(`Name [${mission.name}]: `);
    const description = await ask(`Description [${mission.description ?? 'none'}]: `);
    const status = await ask(`Status [${mission.status}]: `);

    const updates: Record<string, unknown> = {};
    if (name.trim()) updates['name'] = name.trim();
    if (description.trim()) updates['description'] = description.trim();
    if (status.trim()) updates['status'] = status.trim();

    if (Object.keys(updates).length === 0) {
      console.log('No changes.');
      return;
    }

    const updated = await updateMission(gateway, cookie, mission.id, updates);
    console.log(`\nMission "${updated.name}" updated.`);
  } finally {
    rl.close();
  }
}

// ── Task operations ──

async function listTasks(gateway: string, cookie: string, missionId: string) {
  const tasks = await fetchMissionTasks(gateway, cookie, missionId);
  if (tasks.length === 0) {
    console.log('No tasks found.');
    return;
  }
  console.log(`Tasks (${tasks.length}):\n`);
  for (const t of tasks) {
    const desc = t.description ? ` — ${t.description.slice(0, 60)}` : '';
    console.log(`  ${t.id.slice(0, 8)}  ${t.status}${desc}`);
  }
}

async function showTask(gateway: string, cookie: string, missionId: string, taskId: string) {
  const tasks = await fetchMissionTasks(gateway, cookie, missionId);
  const task = tasks.find((t) => t.id === taskId);
  if (!task) {
    console.error(`Task "${taskId}" not found.`);
    process.exit(1);
  }
  showTaskDetail(task);
}

async function createTaskWizard(gateway: string, cookie: string, missionId: string) {
  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    const description = await ask('Task description: ');
    if (!description.trim()) {
      console.error('Description is required.');
      return;
    }

    const status = await ask('Status [not-started]: ');

    const task = await createMissionTask(gateway, cookie, missionId, {
      description: description.trim(),
      status: status.trim() || 'not-started',
    });

    console.log(`\nTask created (${task.id}).`);
  } finally {
    rl.close();
  }
}

async function updateTaskWizard(
  gateway: string,
  cookie: string,
  missionId: string,
  taskId: string,
) {
  const readline = await import('node:readline');
  const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
  const ask = (q: string): Promise<string> => new Promise((resolve) => rl.question(q, resolve));

  try {
    const status = await ask('New status: ');
    const notes = await ask('Notes (optional): ');
    const pr = await ask('PR (optional): ');

    const updates: Record<string, unknown> = {};
    if (status.trim()) updates['status'] = status.trim();
    if (notes.trim()) updates['notes'] = notes.trim();
    if (pr.trim()) updates['pr'] = pr.trim();

    if (Object.keys(updates).length === 0) {
      console.log('No changes.');
      return;
    }

    const updated = await updateMissionTask(gateway, cookie, missionId, taskId, updates);
    console.log(`\nTask ${updated.id.slice(0, 8)} updated (${updated.status}).`);
  } finally {
    rl.close();
  }
}
