/**
 * Thin adapter — delegates all discovery-plan business logic to
 * `src/always-on/web/DiscoveryPlanService.ts`.
 *
 * This file only wires the service's dependency injection and
 * re-exports the public API surface consumed by routes and slash
 * commands.
 */

import { isSessionActiveViaGateway as isClaudeSDKSessionActive, getPilotDeckGateway } from './pilotdeck-bridge.js';
import {
  extractProjectDirectory,
  getProjectCronJobsOverview,
  getSessions,
} from './projects.js';
import { appendAlwaysOnRunEvent } from './services/always-on-run-history.js';
import {
  appendAlwaysOnRunLog,
  appendAlwaysOnRunLogEvent,
  formatAlwaysOnPlanLogLine,
} from './services/always-on-run-logs.js';
import { resolvePilotHome, createProjectId } from './utils/pilotPaths.js';

import { DiscoveryPlanService } from '../../src/always-on/web/DiscoveryPlanService.js';
import { buildDiscoveryContext } from '../../src/always-on/web/DiscoveryPlanContext.js';
import {
  applyWorktreeToProject,
  disposeWorkspace as disposeWorkspaceImpl,
} from '../../src/always-on/workspace/WorkspaceApply.js';

// ---------------------------------------------------------------------------
// Wire dependencies for the service
// ---------------------------------------------------------------------------

function getService() {
  return new DiscoveryPlanService({
    pilotHome: resolvePilotHome(),
    createProjectId,
    paths: { extractProjectDirectory },
    sessions: { getSessions },
    activity: { isSessionActive: isClaudeSDKSessionActive },
    events: {
      appendRunEvent: appendAlwaysOnRunEvent,
      appendRunLog: appendAlwaysOnRunLog,
      appendRunLogEvent: appendAlwaysOnRunLogEvent,
      formatLogLine: formatAlwaysOnPlanLogLine,
    },
    workspace: {
      applyWorktreeChanges: applyWorktreeToProject,
      disposeWorkspace: disposeWorkspaceImpl,
    },
  });
}

// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------

export async function getProjectDiscoveryContext(projectName) {
  const projectRoot = await extractProjectDirectory(projectName);
  return buildDiscoveryContext({
    projectName,
    projectRoot,
    getProjectCronJobsOverview,
    getSessions,
    extractProjectDirectory,
  });
}

export async function getProjectDiscoveryPlansOverview(projectName) {
  return getService().getPlansOverview(projectName);
}

export async function rerunDiscoveryPlan(projectName, planId) {
  const projectRoot = await extractProjectDirectory(projectName);
  const gw = await getPilotDeckGateway();
  const result = await gw.alwaysOnRerunPlan({
    projectKey: projectRoot,
    planId,
    projectName,
  });
  if (result.error) {
    const err = new Error(result.error.message);
    err.code = result.error.code;
    throw err;
  }
  return { runId: result.runId };
}

export async function getProjectDiscoveryPlanReport(projectName, planId) {
  return getService().readReport(projectName, planId);
}

export async function getProjectWorkCycles(projectName) {
  return getService().getCyclesOverview(projectName);
}

export async function archiveWorkCycle(projectName, cycleId) {
  return getService().archiveCycle(projectName, cycleId);
}

export async function applyWorkCycle(projectName, cycleId) {
  const result = await getService().queueCycleApply(projectName, cycleId);

  const gw = await getPilotDeckGateway();

  let applyResult;
  try {
    applyResult = await gw.alwaysOnApply({
      projectKey: result.projectRoot,
      workCycleId: cycleId,
      projectName,
    });
  } catch (err) {
    await getService().updateCycleExecution(projectName, cycleId, {
      status: 'failed',
    });
    return {
      cycle: result.cycle,
      error: { code: 'apply_error', message: (err && err.message) || 'Apply failed' },
    };
  }

  if (applyResult.error) {
    await getService().updateCycleExecution(projectName, cycleId, {
      status: 'failed',
    });
    return { cycle: result.cycle, error: applyResult.error };
  }

  const finalResult = await getService().updateCycleExecution(projectName, cycleId, {
    status: 'completed',
    executionSessionId: applyResult.sessionKey,
  });
  return {
    cycle: finalResult.cycle,
    sessionKey: applyResult.sessionKey,
  };
}