/**
 * Dependency Container
 *
 * Factory functions for creating the full dependency graph.
 * Keeps startServer() thin and makes repo wiring reusable by the test harness.
 */

import type { DrizzleDatabase } from './db/index.js';
import {
  createDatabase,
  ensureSchema,
  DrizzleInitiativeRepository,
  DrizzlePhaseRepository,
  DrizzleTaskRepository,
  DrizzleMessageRepository,
  DrizzleAgentRepository,
  DrizzlePageRepository,
  DrizzleProjectRepository,
  DrizzleAccountRepository,
  DrizzleChangeSetRepository,
  DrizzleLogChunkRepository,
  DrizzleConversationRepository,
  DrizzleChatSessionRepository,
  DrizzleReviewCommentRepository,
  DrizzleErrandRepository,
} from './db/index.js';
import type { InitiativeRepository } from './db/repositories/initiative-repository.js';
import type { PhaseRepository } from './db/repositories/phase-repository.js';
import type { TaskRepository } from './db/repositories/task-repository.js';
import type { MessageRepository } from './db/repositories/message-repository.js';
import type { AgentRepository } from './db/repositories/agent-repository.js';
import type { PageRepository } from './db/repositories/page-repository.js';
import type { ProjectRepository } from './db/repositories/project-repository.js';
import type { AccountRepository } from './db/repositories/account-repository.js';
import type { ChangeSetRepository } from './db/repositories/change-set-repository.js';
import type { LogChunkRepository } from './db/repositories/log-chunk-repository.js';
import type { ConversationRepository } from './db/repositories/conversation-repository.js';
import type { ChatSessionRepository } from './db/repositories/chat-session-repository.js';
import type { ReviewCommentRepository } from './db/repositories/review-comment-repository.js';
import type { ErrandRepository } from './db/repositories/errand-repository.js';
import type { EventBus } from './events/index.js';
import { createEventBus } from './events/index.js';
import { ProcessManager, ProcessRegistry } from './process/index.js';
import { LogManager } from './logging/index.js';
import { MultiProviderAgentManager } from './agent/index.js';
import { DefaultAccountCredentialManager } from './agent/credentials/index.js';
import type { AccountCredentialManager } from './agent/credentials/types.js';
import { DefaultDispatchManager } from './dispatch/manager.js';
import { DefaultPhaseDispatchManager } from './dispatch/phase-manager.js';
import type { DispatchManager, PhaseDispatchManager } from './dispatch/types.js';
import { SimpleGitBranchManager } from './git/simple-git-branch-manager.js';
import type { BranchManager } from './git/branch-manager.js';
import { ProjectSyncManager } from './git/remote-sync.js';
import { ExecutionOrchestrator } from './execution/orchestrator.js';
import { DefaultConflictResolutionService } from './coordination/conflict-resolution-service.js';
import { PreviewManager } from './preview/index.js';
import { findWorkspaceRoot } from './config/index.js';
import { createModuleLogger } from './logger/index.js';
import type { ServerContextDeps } from './server/index.js';

// =============================================================================
// Repositories
// =============================================================================

/**
 * All 13 repository ports.
 */
export interface Repositories {
  initiativeRepository: InitiativeRepository;
  phaseRepository: PhaseRepository;
  taskRepository: TaskRepository;
  messageRepository: MessageRepository;
  agentRepository: AgentRepository;
  pageRepository: PageRepository;
  projectRepository: ProjectRepository;
  accountRepository: AccountRepository;
  changeSetRepository: ChangeSetRepository;
  logChunkRepository: LogChunkRepository;
  conversationRepository: ConversationRepository;
  chatSessionRepository: ChatSessionRepository;
  reviewCommentRepository: ReviewCommentRepository;
  errandRepository: ErrandRepository;
}

/**
 * Create all 13 Drizzle repository adapters from a database instance.
 * Reusable by both the production server and the test harness.
 */
export function createRepositories(db: DrizzleDatabase): Repositories {
  return {
    initiativeRepository: new DrizzleInitiativeRepository(db),
    phaseRepository: new DrizzlePhaseRepository(db),
    taskRepository: new DrizzleTaskRepository(db),
    messageRepository: new DrizzleMessageRepository(db),
    agentRepository: new DrizzleAgentRepository(db),
    pageRepository: new DrizzlePageRepository(db),
    projectRepository: new DrizzleProjectRepository(db),
    accountRepository: new DrizzleAccountRepository(db),
    changeSetRepository: new DrizzleChangeSetRepository(db),
    logChunkRepository: new DrizzleLogChunkRepository(db),
    conversationRepository: new DrizzleConversationRepository(db),
    chatSessionRepository: new DrizzleChatSessionRepository(db),
    reviewCommentRepository: new DrizzleReviewCommentRepository(db),
    errandRepository: new DrizzleErrandRepository(db),
  };
}

// =============================================================================
// Container
// =============================================================================

/**
 * Full dependency graph for the coordination server.
 */
export interface Container extends Repositories {
  db: DrizzleDatabase;
  eventBus: EventBus;
  processManager: ProcessManager;
  logManager: LogManager;
  workspaceRoot: string;
  credentialManager: AccountCredentialManager;
  agentManager: MultiProviderAgentManager;
  dispatchManager: DispatchManager;
  phaseDispatchManager: PhaseDispatchManager;
  branchManager: BranchManager;
  projectSyncManager: ProjectSyncManager;
  executionOrchestrator: ExecutionOrchestrator;
  previewManager: PreviewManager;

  /** Extract the subset of deps that CoordinationServer needs. */
  toContextDeps(): ServerContextDeps;
}

/**
 * Options for container creation.
 */
export interface ContainerOptions {
  debug?: boolean;
}

/**
 * Create the full dependency container.
 *
 * Wires: ProcessRegistry → EventBus → ProcessManager → LogManager →
 *        Database → Repositories → CredentialManager → AgentManager.
 * Runs ensureSchema() and reconcileAfterRestart() before returning.
 */
export async function createContainer(options?: ContainerOptions): Promise<Container> {
  const log = createModuleLogger('container');

  // Infrastructure
  const registry = new ProcessRegistry();
  const eventBus = createEventBus();
  const processManager = new ProcessManager(registry, eventBus);
  const logManager = new LogManager();

  // Database
  const db = createDatabase();
  ensureSchema(db);
  log.info('database initialized');

  // Repositories
  const repos = createRepositories(db);
  log.info('repositories created');

  // Workspace root
  const workspaceRoot = findWorkspaceRoot(process.cwd()) ?? process.cwd();
  log.info({ workspaceRoot }, 'workspace root resolved');

  // Credential manager
  const credentialManager = new DefaultAccountCredentialManager(eventBus);
  log.info('credential manager created');

  // Agent manager
  const agentManager = new MultiProviderAgentManager(
    repos.agentRepository,
    workspaceRoot,
    repos.projectRepository,
    repos.accountRepository,
    eventBus,
    credentialManager,
    repos.changeSetRepository,
    repos.phaseRepository,
    repos.taskRepository,
    repos.pageRepository,
    repos.logChunkRepository,
    options?.debug ?? false,
    undefined, // processManagerOverride
    repos.chatSessionRepository,
    repos.reviewCommentRepository,
  );
  log.info('agent manager created');

  // Reconcile agent state from any previous server session
  await agentManager.reconcileAfterRestart();
  log.info('agent reconciliation complete');

  // Branch manager
  const branchManager = new SimpleGitBranchManager();
  log.info('branch manager created');

  // Project sync manager
  const projectSyncManager = new ProjectSyncManager(
    repos.projectRepository,
    workspaceRoot,
    eventBus,
  );
  log.info('project sync manager created');

  // Dispatch managers
  const dispatchManager = new DefaultDispatchManager(
    repos.taskRepository,
    repos.messageRepository,
    agentManager,
    eventBus,
    repos.initiativeRepository,
    repos.phaseRepository,
    repos.agentRepository,
    repos.pageRepository,
    repos.projectRepository,
    branchManager,
    workspaceRoot,
  );
  const phaseDispatchManager = new DefaultPhaseDispatchManager(
    repos.phaseRepository,
    repos.taskRepository,
    dispatchManager,
    eventBus,
    repos.initiativeRepository,
    repos.projectRepository,
    branchManager,
    workspaceRoot,
    projectSyncManager,
  );
  log.info('dispatch managers created');

  // Conflict resolution service (for orchestrator)
  const conflictResolutionService = new DefaultConflictResolutionService(
    repos.taskRepository,
    repos.agentRepository,
    repos.messageRepository,
    eventBus,
  );

  // Execution orchestrator
  const executionOrchestrator = new ExecutionOrchestrator(
    branchManager,
    repos.phaseRepository,
    repos.taskRepository,
    repos.initiativeRepository,
    repos.projectRepository,
    phaseDispatchManager,
    dispatchManager,
    conflictResolutionService,
    eventBus,
    workspaceRoot,
  );
  executionOrchestrator.start();
  log.info('execution orchestrator started');

  // Preview manager
  const previewManager = new PreviewManager(
    repos.projectRepository,
    eventBus,
    workspaceRoot,
    repos.phaseRepository,
    repos.initiativeRepository,
  );
  log.info('preview manager created');

  return {
    db,
    eventBus,
    processManager,
    logManager,
    workspaceRoot,
    credentialManager,
    agentManager,
    dispatchManager,
    phaseDispatchManager,
    branchManager,
    projectSyncManager,
    executionOrchestrator,
    previewManager,
    ...repos,

    toContextDeps(): ServerContextDeps {
      return {
        agentManager,
        credentialManager,
        dispatchManager,
        phaseDispatchManager,
        branchManager,
        projectSyncManager,
        executionOrchestrator,
        previewManager,
        workspaceRoot,
        ...repos,
      };
    },
  };
}
