import type { Page, Route } from '@playwright/test';
import { agentUser } from '../fixtures/users';
import { registerBaseApiMocks } from './mock-api';

function json(route: Route, body: unknown, status = 200): Promise<void> {
  return route.fulfill({
    status,
    contentType: 'application/json',
    body: JSON.stringify(body),
  });
}

const dept = agentUser.departments[0]!;
const owner = { id: agentUser.id, name: agentUser.name, email: agentUser.email };

const defaultPermissions = {
  role: 'owner' as const,
  can_manage: true,
  can_update_work_items: true,
  can_plan_capacity: true,
};

function makeProjectSummary(
  id: string,
  name: string,
  key: string,
  overrides: Record<string, unknown> = {},
) {
  return {
    id,
    company_id: agentUser.company_id,
    department_id: dept.id,
    department: { id: dept.id, name: dept.name, code: 'IT' },
    owner_user_id: agentUser.id,
    owner,
    name,
    key,
    description: null,
    status: 'active',
    start_date: '2026-06-01',
    due_date: '2026-12-31',
    completed_at: null,
    color: '#6366f1',
    permissions: defaultPermissions,
    completion_percentage: 10,
    health_level: 'healthy',
    active_sprint: null,
    is_overdue: false,
    created_at: new Date().toISOString(),
    updated_at: new Date().toISOString(),
    ...overrides,
  };
}

function makeWorkItem(
  id: string,
  subject: string,
  opts: {
    sprint_id?: string | null;
    epic_id?: string | null;
    epic?: { id: string; name: string; color: string | null } | null;
    ticket_number?: string;
    estimate_md?: number;
  } = {},
) {
  return {
    id,
    ticket_number: opts.ticket_number ?? `E2E-${id.slice(-4).toUpperCase()}`,
    subject,
    work_type: 'backlog_item',
    project_id: null as string | null,
    sprint_id: opts.sprint_id ?? null,
    epic_id: opts.epic_id ?? null,
    backlog_order: 1,
    sprint_order: null,
    start_date: null,
    due_date: null,
    completed_at: null,
    estimate_md: opts.estimate_md ?? 2,
    estimate_points: null,
    is_overdue: false,
    dependency_count: 0,
    comment_count: 0,
    epic: opts.epic ?? null,
    assignee: null,
    status: { id: 'st-1', name_en: 'Open', color: '#22c55e' },
    priority: { id: 'pr-1', name_en: 'Normal', color: '#6366f1' },
  };
}

export class ProjectMockStore {
  projectId = 'proj-e2e-001';
  projectName = 'E2E Agile Project';
  projectKey = 'E2EAG';
  permissions: {
    role: 'owner' | 'manager' | 'agent' | 'viewer';
    can_manage: boolean;
    can_update_work_items: boolean;
    can_plan_capacity: boolean;
  } = { ...defaultPermissions };
  epics: Array<{ id: string; name: string; color: string | null; description?: string | null }> = [];
  sprints: Array<{
    id: string;
    project_id: string;
    name: string;
    goal: string | null;
    status: 'draft' | 'planned' | 'active' | 'completed' | 'cancelled' | 'archived';
    start_date: string;
    due_date: string;
    completed_at: string | null;
    sort_order: number;
    is_overdue: boolean;
    capacity_md?: number | null;
    committed_md?: number;
  }> = [];
  backlogItems: ReturnType<typeof makeWorkItem>[] = [];
  sprintItems: ReturnType<typeof makeWorkItem>[] = [];
  risks: Array<{
    id: string;
    project_id: string;
    title: string;
    description: string | null;
    probability: number;
    impact: number;
    owner_user_id: string | null;
    status: 'open' | 'mitigated' | 'closed';
    mitigation_plan: string | null;
  }> = [];
  milestones: Array<{ id: string; name: string; due_date: string; status: string }> = [];
  dependencies: Array<{
    id: string;
    source_ticket_id: string;
    target_ticket_id: string;
    type: string;
    resolved: boolean;
    source?: { id: string; ticket_number: string; subject: string };
    target?: { id: string; ticket_number: string; subject: string };
  }> = [];

  private idSeq = 0;

  nextId(prefix: string): string {
    this.idSeq += 1;
    return `${prefix}-${this.idSeq}`;
  }

  get project() {
    return makeProjectSummary(this.projectId, this.projectName, this.projectKey, {
      active_sprint: this.sprints.find((s) => s.status === 'active') ?? this.sprints[0] ?? null,
      permissions: this.permissions,
    });
  }

  backlogDashboard() {
    const items = this.backlogItems.map((item) => ({
      ...item,
      project_id: this.projectId,
    }));
    return {
      metrics: {
        total: items.length + this.sprintItems.length,
        ready_for_sprint: items.length,
        in_sprint: this.sprintItems.length,
        blocked: 0,
        completed: 0,
        overdue: 0,
      },
      empty_state: items.length === 0 && this.sprintItems.length === 0 ? 'no_items' : 'has_items',
      analytics: {
        avg_business_value: items.length ? 62 : null,
        labeled_items: Math.min(items.length, 12),
        epic_progress: this.epics.slice(0, 6).map((e, idx) => ({
          epic_id: e.id,
          name: e.name,
          total: 8,
          completed: idx + 1,
          progress_percent: Math.round(((idx + 1) / 8) * 100),
        })),
        priority_distribution: { 'pr-1': items.length },
      },
      items,
      epic_groups: [],
      filters: {},
    };
  }

  riskMatrix() {
    const cells: Array<{
      probability: number;
      impact: number;
      score: number;
      count: number;
      risks: Array<{ id: string; title: string; category?: string; status: string }>;
    }> = [];
    for (let p = 1; p <= 5; p += 1) {
      for (let i = 1; i <= 5; i += 1) {
        const cellRisks = this.risks
          .filter((r) => r.probability === p && r.impact === i && r.status === 'open')
          .map((r) => ({ id: r.id, title: r.title, status: r.status }));
        cells.push({ probability: p, impact: i, score: p * i, count: cellRisks.length, risks: cellRisks });
      }
    }
    return {
      cells,
      total_open: this.risks.filter((r) => r.status === 'open').length,
      critical: this.risks.filter((r) => r.status === 'open' && r.probability * r.impact >= 15).length,
    };
  }

  milestoneTimeline() {
    return this.milestones.map((m, idx) => ({
      id: m.id,
      name: m.name,
      due_date: m.due_date,
      status: m.status,
      progress_percent: Math.min(100, idx * 20),
      is_overdue: false,
      days_variance: 0,
      health: idx % 3 === 0 ? 'at_risk' : 'on_track',
    }));
  }

  blockedChains() {
    const chains = this.dependencies.slice(0, 10).map((d) => ({
      dependency_id: d.id,
      type: d.type,
      chain: [d.source?.ticket_number ?? 'A', d.target?.ticket_number ?? 'B'],
      depth: 2,
      source: d.source ?? { id: '', ticket_number: 'A', subject: 'Source' },
      target: d.target ?? { id: '', ticket_number: 'B', subject: 'Target' },
    }));
    return { chains, count: chains.length };
  }

  seedUatData() {
    this.epics = Array.from({ length: 10 }, (_, i) => ({
      id: this.nextId('epic'),
      name: `UAT Epic ${i + 1}`,
      color: ['#6366f1', '#22c55e', '#f59e0b', '#ef4444', '#06b6d4'][i % 5],
      description: `Epic ${i + 1} scope`,
    }));

    this.sprints = Array.from({ length: 5 }, (_, i) => ({
      id: this.nextId('sprint'),
      project_id: this.projectId,
      name: `UAT Sprint ${i + 1}`,
      goal: `Deliver increment ${i + 1}`,
      status: i === 0 ? ('active' as const) : i < 4 ? ('completed' as const) : ('planned' as const),
      start_date: '2026-06-01',
      due_date: '2026-06-14',
      completed_at: i > 0 && i < 4 ? '2026-06-14' : null,
      sort_order: i,
      is_overdue: false,
      capacity_md: 20,
      committed_md: 16,
    }));

    this.backlogItems = Array.from({ length: 40 }, (_, i) => {
      const epic = this.epics[i % this.epics.length];
      return makeWorkItem(this.nextId('wi'), `UAT Story ${i + 1}`, {
        ticket_number: `UAT-${100 + i}`,
        epic_id: epic.id,
        epic: { id: epic.id, name: epic.name, color: epic.color },
        estimate_md: (i % 5) + 1,
      });
    });

    this.sprintItems = Array.from({ length: 12 }, (_, i) =>
      makeWorkItem(this.nextId('wi'), `UAT Sprint Task ${i + 1}`, {
        ticket_number: `UAT-${200 + i}`,
        sprint_id: this.sprints[0].id,
        estimate_md: (i % 4) + 1,
      }),
    );

    this.risks = Array.from({ length: 10 }, (_, i) => ({
      id: this.nextId('risk'),
      project_id: this.projectId,
      title: `UAT Risk ${i + 1}`,
      description: `Risk ${i + 1} description`,
      probability: (i % 5) + 1,
      impact: ((i + 2) % 5) + 1,
      owner_user_id: owner.id,
      status: 'open' as const,
      mitigation_plan: i % 2 === 0 ? 'Mitigation underway' : null,
    }));

    this.milestones = Array.from({ length: 6 }, (_, i) => ({
      id: this.nextId('ms'),
      name: `UAT Milestone ${i + 1}`,
      due_date: `2026-${String(7 + i).padStart(2, '0')}-15`,
      status: i < 2 ? 'completed' : 'upcoming',
    }));

    const allItems = [...this.backlogItems, ...this.sprintItems];
    this.dependencies = Array.from({ length: 20 }, (_, i) => {
      const source = allItems[i];
      const target = allItems[i + 1];
      return {
        id: this.nextId('dep'),
        source_ticket_id: source.id,
        target_ticket_id: target.id,
        type: (['FS', 'SS', 'FF', 'SF'] as const)[i % 4],
        resolved: false,
        source: { id: source.id, ticket_number: source.ticket_number, subject: source.subject },
        target: { id: target.id, ticket_number: target.ticket_number, subject: target.subject },
      };
    });
  }

  capacityPlanning() {
    const sprint = this.sprints.find((s) => s.status === 'active') ?? this.sprints[0];
    const members = [owner, { id: 'u-2', name: 'Sara Dev' }, { id: 'u-3', name: 'Omar QA' }];
    const team = members.map((m, i) => {
      const capacity = 20;
      const assigned = [14, 22, 8][i] ?? 12;
      const remaining = capacity - assigned;
      const utilization = Math.round((assigned / capacity) * 100);
      const health: 'green' | 'yellow' | 'orange' | 'red' =
        utilization > 100 ? 'red' : utilization >= 90 ? 'orange' : utilization >= 75 ? 'yellow' : 'green';
      return {
        user_id: m.id,
        name: m.name,
        role: i === 0 ? 'Owner' : 'Member',
        capacity_md: capacity,
        assigned_md: assigned,
        remaining_md: remaining,
        utilization_percent: utilization,
        health,
        overload_md: remaining < 0 ? Math.abs(remaining) : 0,
        recommendation: remaining < 0 ? 'Rebalance work' : undefined,
      };
    });
    return {
      sprint: {
        id: sprint?.id ?? 'sprint-1',
        name: sprint?.name ?? 'UAT Sprint 1',
        start_date: sprint?.start_date ?? '2026-06-01',
        due_date: sprint?.due_date ?? '2026-06-14',
      },
      metrics: {
        total_capacity_md: team.reduce((s, t) => s + t.capacity_md, 0),
        assigned_md: team.reduce((s, t) => s + t.assigned_md, 0),
        remaining_md: team.reduce((s, t) => s + t.remaining_md, 0),
        overallocated_users: team.filter((t) => t.overload_md > 0).length,
      },
      team,
    };
  }

  executiveDashboard() {
    return {
      project: {
        id: this.projectId,
        name: this.projectName,
        key: this.projectKey,
        status: 'active',
        start_date: '2026-06-01',
        due_date: '2026-12-31',
        is_overdue: false,
        completion_percent: 25,
      },
      health: {
        score: 82,
        level: 'healthy',
        explanation: ['Delivery on track for E2E validation.'],
        breakdown: {
          work_items: { total: 4, completed: 1, blocked: 0, overdue: 0, completion_rate: 25 },
          risks: { open: this.risks.filter((r) => r.status === 'open').length, critical: 0, total: this.risks.length },
          milestones: {
            total: this.milestones.length,
            completed: this.milestones.filter((m) => m.status === 'completed').length,
            overdue: 0,
          },
          dependencies: { total: this.dependencies.length, blocking: 0 },
        },
      },
      risk_summary: {
        total: this.risks.length,
        open: this.risks.filter((r) => r.status === 'open').length,
        critical: this.risks.filter((r) => r.probability * r.impact >= 15).length,
        mitigated: this.risks.filter((r) => r.status === 'mitigated').length,
        closed: this.risks.filter((r) => r.status === 'closed').length,
        by_category: {},
        by_status: {},
        matrix: [],
        total_risk_score: this.risks.reduce((sum, r) => sum + r.probability * r.impact, 0),
      },
      risk_trend: [
        { date: '2026-05-01', score: 40, level: 'medium' },
        { date: '2026-05-15', score: 55, level: 'high' },
        { date: '2026-06-01', score: 48, level: 'medium' },
      ],
      velocity: {
        current: 15,
        trend: 'up',
        history: this.sprints
          .filter((s) => s.status === 'completed')
          .map((s, i) => ({
            sprint_id: s.id,
            sprint_name: s.name,
            completed_at: s.completed_at ?? '2026-06-14',
            velocity_md: 12 + i * 2,
            completed_items: 8 + i,
          })),
      },
      burndown: {
        sprint_id: this.sprints[0]?.id ?? 'sprint-1',
        sprint_name: this.sprints[0]?.name ?? 'UAT Sprint 1',
        start_date: '2026-06-01',
        due_date: '2026-06-14',
        current_remaining_md: 9,
        expected_remaining_md: 7,
        variance_percent: 28,
        status: 'at_risk',
        chart_data: {
          ideal: [
            { date: '2026-06-01', value: 16 },
            { date: '2026-06-07', value: 8 },
            { date: '2026-06-14', value: 0 },
          ],
          actual: [
            { date: '2026-06-01', value: 16 },
            { date: '2026-06-07', value: 11 },
            { date: '2026-06-14', value: 9 },
          ],
        },
      },
      blocked_work: { count: 1, items: [] },
      open_dependencies: { count: this.dependencies.length, items: [] },
      upcoming_milestones: this.milestones.map((m) => ({
        id: m.id,
        name: m.name,
        due_date: m.due_date,
        status: m.status,
        is_overdue: false,
        days_until: 30,
        progress_percent: 0,
      })),
      sprint_status: this.sprints[0]
        ? {
            has_active: true,
            sprint: {
              id: this.sprints[0].id,
              name: this.sprints[0].name,
              start_date: this.sprints[0].start_date,
              due_date: this.sprints[0].due_date,
              goal: this.sprints[0].goal,
            },
            health: { status: 'good', score: 80 },
            progress: { time_percent: 40, days_remaining: 10, is_overdue: false },
            items: { total: this.sprintItems.length, completed: 0, in_progress: 1, todo: 1 },
            next_sprint: null,
          }
        : null,
      capacity_utilization: {
        total_capacity_md: 100,
        assigned_md: 72,
        remaining_capacity_md: 28,
        utilization_percent: 72,
        status: 'near_capacity',
        team_members: 5,
        overloaded_members: 1,
      },
      forecast: {
        can_forecast: true,
        remaining_work_md: 48,
        average_velocity_md: 15,
        sprints_remaining: 4,
        days_remaining: 56,
        forecast_date: '2026-08-15',
        project_due_date: '2026-12-31',
        is_late: false,
        days_variance: 138,
      },
      attention_items: [
        {
          type: 'risk',
          severity: 'high',
          title: 'Critical risk needs mitigation',
          description: 'A high-impact risk is open.',
          entity_id: this.risks[0]?.id ?? 'risk-1',
          action: 'Review risk register',
        },
        {
          type: 'sprint',
          severity: 'medium',
          title: 'Sprint burndown behind ideal',
          description: 'Remaining work is above the ideal line.',
          entity_id: this.sprints[0]?.id ?? 'sprint-1',
          action: 'Check sprint board',
        },
      ],
    };
  }

  commandCenter() {
    const activeSprint = this.sprints.find((s) => s.status === 'active') ?? this.sprints[0] ?? null;
    return {
      project_health: { score: 82, level: 'healthy', components: { delivery: 80, risk: 75, schedule: 85 } },
      progress_percent: 28,
      open_work_count: this.backlogItems.length + this.sprintItems.length,
      completed_work_count: 6,
      open_work_md: 48,
      active_sprint: activeSprint
        ? {
            sprint: {
              id: activeSprint.id,
              name: activeSprint.name,
              start_date: activeSprint.start_date,
              due_date: activeSprint.due_date,
            },
            health: { status: 'good', score: 80 },
            burndown: {
              ideal_line: [
                { date: '2026-06-01', value: 16 },
                { date: '2026-06-14', value: 0 },
              ],
              actual_line: [
                { date: '2026-06-01', value: 16 },
                { date: '2026-06-07', value: 9 },
              ],
              remaining_md: [{ date: '2026-06-07', value: 9 }],
              completed_md: [{ date: '2026-06-07', value: 7 }],
              total_md: 16,
            },
          }
        : null,
      velocity: {
        sprints: this.sprints
          .filter((s) => s.status === 'completed')
          .map((s) => ({ sprint_id: s.id, sprint_name: s.name, completed_md: 15 })),
        average_velocity_md: 15,
        best_sprint_md: 18,
        worst_sprint_md: 12,
        trend: 'stable',
        windows: { last_3: 15, last_5: 15, last_10: 15 },
      },
      risks_open: this.risks.filter((r) => r.status === 'open').length,
      dependencies_count: this.dependencies.length,
      overdue_work_count: 2,
      blocked_work_count: 1,
      team_capacity: null,
      upcoming_milestones: this.milestones
        .filter((m) => m.status !== 'completed')
        .map((m) => ({ id: m.id, name: m.name, due_date: m.due_date, status: m.status })),
      recent_activity: [
        { event: 'work_item.created', action: 'created', created_at: new Date().toISOString() },
        { event: 'sprint.started', action: 'started', created_at: new Date().toISOString() },
      ],
    };
  }

  ganttTimeline() {
    const items = this.backlogItems.slice(0, 12).map((it, idx) => ({
      id: it.id,
      entity_id: it.id,
      entity_type: 'work_item',
      title: it.subject,
      start_date: `2026-06-${String((idx % 20) + 1).padStart(2, '0')}`,
      end_date: `2026-06-${String((idx % 20) + 4).padStart(2, '0')}`,
      progress_percentage: (idx * 8) % 100,
      status: 'in_progress',
      parent_id: null,
      depends_on: idx > 0 ? [this.backlogItems[idx - 1].id] : [],
      blocked_by: [],
      owner: null,
      priority: 'Normal',
      color: '#6366f1',
      is_delayed: idx % 5 === 0,
      is_blocked: false,
      is_milestone: false,
    }));
    const milestones = this.milestones.map((m) => ({
      id: m.id,
      entity_id: m.id,
      entity_type: 'milestone',
      title: m.name,
      start_date: m.due_date,
      end_date: m.due_date,
      progress_percentage: m.status === 'completed' ? 100 : 0,
      status: m.status,
      parent_id: null,
      depends_on: [],
      blocked_by: [],
      is_delayed: false,
      is_blocked: false,
      is_milestone: true,
    }));
    return {
      project: {
        id: this.projectId,
        name: this.projectName,
        key: this.projectKey,
        status: 'active',
        health: 'healthy',
        progress_percentage: 28,
      },
      timeline: items,
      dependencies: this.dependencies.slice(0, 10).map((d) => ({
        id: d.id,
        from: d.source_ticket_id,
        to: d.target_ticket_id,
        type: d.type,
      })),
      milestones,
      summary: {
        total_items: items.length,
        completed_items: 3,
        blocked_items: 0,
        delayed_items: items.filter((i) => i.is_delayed).length,
        upcoming_milestones: milestones.filter((m) => m.status !== 'completed').length,
      },
    };
  }

  reportsHub() {
    return [
      { key: 'velocity', metric: '5 MD avg' },
      { key: 'burndown', metric: '12 MD left' },
      { key: 'burnup', metric: this.sprints[0]?.name ?? 'No active sprint' },
      { key: 'throughput', metric: '2 done' },
      { key: 'lead-time', metric: 'Delivery speed' },
      { key: 'cycle-time', metric: 'Active work time' },
      { key: 'sprint-health', metric: 'good' },
      { key: 'capacity-trend', metric: `${this.sprints.length} sprints` },
      { key: 'risk-trend', metric: `${this.risks.length} open` },
      { key: 'dependency-trend', metric: `${this.dependencies.length} links` },
      { key: 'work-distribution', metric: '4 items' },
      { key: 'assignee-load', metric: this.sprints[0]?.name ?? 'No sprint' },
      { key: 'epic-progress', metric: `${this.epics.length} epics` },
      { key: 'release-progress', metric: '0 releases' },
    ];
  }

  velocityReport() {
    return {
      meta: {
        project_id: this.projectId,
        report_type: 'velocity',
      },
      summary: {
        average_velocity_md: 5,
        trend: 'stable',
        total_sprints: this.sprints.length,
        total_completed_items: 2,
      },
      chart: {
        labels: this.sprints.length ? this.sprints.map((s) => s.name) : ['Sprint 1'],
        datasets: [{ label: 'Velocity (MD)', data: this.sprints.length ? this.sprints.map(() => 5) : [5] }],
      },
      table: {
        headers: ['Sprint', 'Velocity MD'],
        rows: [{ sprint: 'Sprint 1', velocity_md: 5 }],
      },
    };
  }
}

export const projectMockStore = new ProjectMockStore();

async function handleProjectRoute(route: Route, store: ProjectMockStore): Promise<boolean> {
  const url = new URL(route.request().url());
  const path = url.pathname.replace(/.*\/api\/v1/, '');
  const method = route.request().method();

  if (path === '/projects' && method === 'GET') {
    await json(route, {
      data: [store.project],
      meta: { current_page: 1, last_page: 1, per_page: 24, total: 1 },
    });
    return true;
  }

  if (path === '/projects' && method === 'POST') {
    const body = route.request().postDataJSON() as { name?: string };
    if (body?.name) {
      store.projectName = String(body.name);
      store.projectKey = store.projectName
        .replace(/[^a-zA-Z0-9]/g, '')
        .slice(0, 6)
        .toUpperCase() || 'E2E';
    }
    await json(route, { data: store.project }, 201);
    return true;
  }

  const projectMatch = path.match(/^\/projects\/([^/]+)$/);
  if (projectMatch && method === 'GET') {
    await json(route, { data: store.project });
    return true;
  }

  const pid = store.projectId;

  if (path === `/projects/${pid}/backlog` && method === 'GET') {
    await json(route, { data: store.backlogDashboard() });
    return true;
  }

  if (path === `/projects/${pid}/epics` && method === 'GET') {
    await json(route, { data: store.epics });
    return true;
  }

  if (path === `/projects/${pid}/epics` && method === 'POST') {
    const body = route.request().postDataJSON() as { name?: string; color?: string; description?: string };
    const epic = {
      id: store.nextId('epic'),
      name: String(body?.name ?? 'Epic'),
      color: body?.color ?? '#6366f1',
      description: body?.description ?? null,
    };
    store.epics.push(epic);
    await json(route, { data: epic }, 201);
    return true;
  }

  if (path === `/projects/${pid}/backlog/tickets` && method === 'POST') {
    const body = route.request().postDataJSON() as { subject?: string; epic_id?: string };
    const epic = store.epics.find((e) => e.id === body?.epic_id);
    const item = makeWorkItem(store.nextId('wi'), String(body?.subject ?? 'Item'), {
      epic_id: epic?.id ?? null,
      epic: epic ? { id: epic.id, name: epic.name, color: epic.color } : null,
    });
    store.backlogItems.push(item);
    await json(route, { data: { ...item, project_id: pid } }, 201);
    return true;
  }

  if (path === `/projects/${pid}/sprints` && method === 'GET') {
    await json(route, { data: store.sprints });
    return true;
  }

  if (path === `/projects/${pid}/sprints` && method === 'POST') {
    const body = route.request().postDataJSON() as {
      name?: string;
      goal?: string;
      start_date?: string;
      due_date?: string;
      capacity_md?: number;
    };
    const sprint = {
      id: store.nextId('sprint'),
      project_id: pid,
      name: String(body?.name ?? 'Sprint'),
      goal: body?.goal ?? null,
      status: 'planned' as const,
      start_date: body?.start_date ?? '2026-06-10',
      due_date: body?.due_date ?? '2026-06-24',
      completed_at: null,
      sort_order: store.sprints.length,
      is_overdue: false,
      capacity_md: body?.capacity_md ?? 20,
      committed_md: 0,
    };
    if (store.sprints.every((s) => s.status !== 'active')) {
      sprint.status = 'active';
    }
    store.sprints.push(sprint);
    await json(route, { data: sprint }, 201);
    return true;
  }

  const sprintTicketsMatch = path.match(new RegExp(`^/projects/${pid}/sprints/([^/]+)/tickets$`));
  if (sprintTicketsMatch && method === 'GET') {
    const sprintId = sprintTicketsMatch[1];
    const items = store.sprintItems
      .filter((i) => i.sprint_id === sprintId)
      .map((i) => ({ ...i, project_id: pid }));
    await json(route, { data: items });
    return true;
  }

  const sprintCapacityMatch = path.match(
    new RegExp(`^/projects/${pid}/sprints/([^/]+)/capacity$`),
  );
  if (sprintCapacityMatch && method === 'GET') {
    const sprint = store.sprints.find((s) => s.id === sprintCapacityMatch[1]);
    await json(route, {
      data: {
        committed_md: store.sprintItems.reduce((s, i) => s + (i.estimate_md ?? 0), 0),
        capacity_md: sprint?.capacity_md ?? 20,
        remaining_md: 10,
        utilization_percent: 40,
      },
    });
    return true;
  }

  const moveToSprintMatch = path.match(
    new RegExp(`^/projects/${pid}/tickets/([^/]+)/move-to-sprint/([^/]+)$`),
  );
  if (moveToSprintMatch && method === 'PATCH') {
    const ticketId = moveToSprintMatch[1];
    const sprintId = moveToSprintMatch[2];
    const idx = store.backlogItems.findIndex((i) => i.id === ticketId);
    if (idx >= 0) {
      const [item] = store.backlogItems.splice(idx, 1);
      item.sprint_id = sprintId;
      store.sprintItems.push(item);
      await json(route, { data: { ...item, project_id: pid, sprint_id: sprintId } });
      return true;
    }
    await json(route, { data: {} });
    return true;
  }

  const moveToBacklogMatch = path.match(
    new RegExp(`^/projects/${pid}/tickets/([^/]+)/move-to-backlog$`),
  );
  if (moveToBacklogMatch && method === 'PATCH') {
    const ticketId = moveToBacklogMatch[1];
    const idx = store.sprintItems.findIndex((i) => i.id === ticketId);
    if (idx >= 0) {
      const [item] = store.sprintItems.splice(idx, 1);
      item.sprint_id = null;
      store.backlogItems.push(item);
      await json(route, { data: { ...item, project_id: pid, sprint_id: null } });
      return true;
    }
    await json(route, { data: {} });
    return true;
  }

  if (path === `/projects/${pid}/risks/matrix` && method === 'GET') {
    await json(route, { data: store.riskMatrix() });
    return true;
  }

  const riskHistoryMatch = path.match(new RegExp(`^/projects/${pid}/risks/([^/]+)/history$`));
  if (riskHistoryMatch && method === 'GET') {
    await json(route, {
      data: [
        {
          id: 'rh-1',
          field_changed: 'created',
          old_value: null,
          new_value: 'open',
          changed_by: owner.name,
          changed_at: new Date().toISOString(),
        },
      ],
    });
    return true;
  }

  const riskUpdateMatch = path.match(new RegExp(`^/projects/${pid}/risks/([^/]+)$`));
  if (riskUpdateMatch && method === 'PATCH') {
    const risk = store.risks.find((r) => r.id === riskUpdateMatch[1]);
    const body = route.request().postDataJSON() as { status?: string };
    if (risk && body?.status) {
      risk.status = body.status as typeof risk.status;
    }
    await json(route, { data: risk ?? {} });
    return true;
  }

  if (path === `/projects/${pid}/milestones/timeline` && method === 'GET') {
    await json(route, { data: store.milestoneTimeline() });
    return true;
  }

  if (path === `/projects/${pid}/dependencies/blocked-chains` && method === 'GET') {
    await json(route, { data: store.blockedChains() });
    return true;
  }

  if (path === `/projects/${pid}/backlog/bulk` && method === 'PATCH') {
    const body = route.request().postDataJSON() as { ticket_ids?: string[] };
    await json(route, { message: 'Backlog items updated.', updated_count: body?.ticket_ids?.length ?? 0 });
    return true;
  }

  if (path === `/projects/${pid}/risks` && method === 'GET') {
    const open = store.risks.filter((r) => r.status === 'open').length;
    const critical = store.risks.filter((r) => r.probability * r.impact >= 15).length;
    await json(route, {
      data: store.risks,
      metrics: { open, critical, closed: store.risks.filter((r) => r.status === 'closed').length },
    });
    return true;
  }

  if (path === `/projects/${pid}/risks` && method === 'POST') {
    const body = route.request().postDataJSON() as { title?: string; probability?: number; impact?: number };
    const risk = {
      id: store.nextId('risk'),
      project_id: pid,
      title: String(body?.title ?? 'Risk'),
      description: null,
      probability: body?.probability ?? 3,
      impact: body?.impact ?? 3,
      owner_user_id: agentUser.id,
      status: 'open' as const,
      mitigation_plan: null,
    };
    store.risks.push(risk);
    await json(route, { data: risk }, 201);
    return true;
  }

  if (path === `/projects/${pid}/milestones` && method === 'GET') {
    await json(route, {
      data: store.milestones,
      metrics: {
        upcoming: store.milestones.filter((m) => m.status !== 'completed').length,
        overdue: 0,
        completed: store.milestones.filter((m) => m.status === 'completed').length,
      },
    });
    return true;
  }

  if (path === `/projects/${pid}/milestones` && method === 'POST') {
    const body = route.request().postDataJSON() as { title?: string; due_date?: string };
    const milestone = {
      id: store.nextId('ms'),
      name: String(body?.title ?? 'Milestone'),
      due_date: body?.due_date ?? '2026-09-01',
      status: 'upcoming',
    };
    store.milestones.push(milestone);
    await json(route, { data: milestone }, 201);
    return true;
  }

  if (path === `/projects/${pid}/dependencies` && method === 'GET') {
    await json(route, {
      data: {
        metrics: {
          total: store.dependencies.length,
          blocking: 0,
          unresolved: store.dependencies.filter((d) => !d.resolved).length,
          blocked_work: 0,
        },
        items: store.dependencies,
      },
    });
    return true;
  }

  if (path === `/projects/${pid}/dependencies` && method === 'POST') {
    const body = route.request().postDataJSON() as {
      source_ticket_id?: string;
      target_ticket_id?: string;
      dependency_type?: string;
    };
    const source = [...store.backlogItems, ...store.sprintItems].find(
      (i) => i.id === body?.source_ticket_id,
    );
    const target = [...store.backlogItems, ...store.sprintItems].find(
      (i) => i.id === body?.target_ticket_id,
    );
    const dep = {
      id: store.nextId('dep'),
      source_ticket_id: body?.source_ticket_id ?? '',
      target_ticket_id: body?.target_ticket_id ?? '',
      type: body?.dependency_type ?? 'FS',
      resolved: false,
      source: source
        ? { id: source.id, ticket_number: source.ticket_number, subject: source.subject }
        : undefined,
      target: target
        ? { id: target.id, ticket_number: target.ticket_number, subject: target.subject }
        : undefined,
    };
    store.dependencies.push(dep);
    await json(route, { data: dep }, 201);
    return true;
  }

  const workItemSearchMatch = path.match(new RegExp(`^/projects/${pid}/work-items/search$`));
  if (workItemSearchMatch && method === 'GET') {
    const q = url.searchParams.get('q')?.toLowerCase() ?? '';
    const all = [...store.backlogItems, ...store.sprintItems];
    const hits = all
      .filter(
        (i) =>
          i.subject.toLowerCase().includes(q) ||
          i.ticket_number.toLowerCase().includes(q),
      )
      .map((i) => ({
        id: i.id,
        ticket_number: i.ticket_number,
        subject: i.subject,
        label: `${i.ticket_number} — ${i.subject}`,
      }));
    await json(route, { data: hits });
    return true;
  }

  if (path === `/projects/${pid}/members` && method === 'GET') {
    await json(route, {
      data: [
        {
          id: 'mem-1',
          project_id: pid,
          user_id: agentUser.id,
          role: 'owner',
          user: owner,
        },
      ],
    });
    return true;
  }

  if (path === `/projects/${pid}/command-center` && method === 'GET') {
    await json(route, { data: store.commandCenter() });
    return true;
  }

  if (path === `/projects/${pid}/capacity-planning` && method === 'GET') {
    await json(route, { data: store.capacityPlanning() });
    return true;
  }

  if (path === `/projects/${pid}/gantt` && method === 'GET') {
    await json(route, { data: store.ganttTimeline() });
    return true;
  }

  if (path === `/projects/${pid}/executive-dashboard` && method === 'GET') {
    await json(route, { data: store.executiveDashboard() });
    return true;
  }

  if (path === `/projects/${pid}/reports-hub` && method === 'GET') {
    await json(route, { data: store.reportsHub() });
    return true;
  }

  const reportMatch = path.match(new RegExp(`^/projects/${pid}/reports/([a-z0-9-]+)$`));
  if (reportMatch && method === 'GET') {
    const key = reportMatch[1];
    const payload =
      key === 'velocity'
        ? store.velocityReport()
        : {
            summary: {},
            chart: { labels: ['A'], datasets: [{ label: 'Series', data: [1] }] },
          };
    await json(route, { data: payload });
    return true;
  }

  const exportMatch = path.match(new RegExp(`^/projects/${pid}/reports/export/([a-z_]+)$`));
  if (exportMatch && method === 'GET') {
    await route.fulfill({
      status: 200,
      contentType: 'text/csv',
      body: 'metric,value\nvelocity_md,5\n',
      headers: {
        'Content-Disposition': 'attachment; filename="velocity-report.csv"',
      },
    });
    return true;
  }

  if (path === `/projects/${pid}/backlog/reorder` && method === 'PATCH') {
    await json(route, { success: true });
    return true;
  }

  return false;
}

export async function registerProjectApiMocks(
  page: Page,
  store: ProjectMockStore = projectMockStore,
): Promise<void> {
  await registerBaseApiMocks(page);

  await page.route('**/api/v1/projects**', async (route) => {
    const handled = await handleProjectRoute(route, store);
    if (!handled) {
      await json(route, { data: [] });
    }
  });

  await page.route('**/api/v1/portfolio/**', (route) => json(route, { data: [] }));

  await page.route('**/api/v1/onboarding/**', (route) =>
    json(route, {
      data: {
        persona: 'agent',
        department_id: dept.id,
        should_show_wizard: false,
        onboarding_step: null,
        onboarding_completed_at: new Date().toISOString(),
        dismissed_tours: [],
        checklist: { persona: 'agent', steps: [], completed_steps: [] },
      },
    }),
  );

  await page.route('**/api/v1/dashboard/ticket-trends**', (route) =>
    json(route, { data: { labels: [], datasets: [] } }),
  );
  await page.route('**/api/v1/dashboard/assignee-performance**', (route) =>
    json(route, { data: { assignees: [] } }),
  );
}

export function resetProjectMockStore(store: ProjectMockStore = projectMockStore): void {
  store.projectId = 'proj-e2e-001';
  store.projectName = 'E2E Agile Project';
  store.projectKey = 'E2EAG';
  store.permissions = { ...defaultPermissions };
  store.epics = [];
  store.sprints = [];
  store.backlogItems = [];
  store.sprintItems = [];
  store.risks = [];
  store.milestones = [];
  store.dependencies = [];
  store.idSeq = 0;
}
