import type {
  AgentRunId,
  AttemptId,
  AuditRecord,
  BusinessEvent,
  ChangeSetId,
  ConnectionId,
  CredentialReferenceId,
  FactoryRunId,
  GoalId,
  OutboxMessageId,
  PlanId,
  PlanRevisionId,
  ProjectId,
  ProjectVisionVersionId,
  ProviderReference,
  PrincipalId,
  ReviewId,
  ReviewFindingId,
  VerificationEvidenceId,
  TaskId,
  WorkspaceId,
} from "@awp/contracts";
import type {
  AgentRun,
  Attempt,
  ChangeSet,
  CredentialAuthority,
  FactoryRun,
  Goal,
  Plan,
  PlanRevision,
  Project,
  ProjectVisionVersion,
  Review,
  ReviewFinding,
  VerificationEvidence,
  Task,
  Workspace,
} from "@awp/domain";

export interface EntityRepository<T, Id> {
  getById(id: Id): Promise<T | undefined>;
  insert(entity: T): Promise<void>;
  update(entity: T): Promise<void>;
}

export interface ProjectRepository extends EntityRepository<Project, ProjectId> {
  list(): Promise<readonly Project[]>;
}
export interface ProjectVisionRepository {
  getById(id: ProjectVisionVersionId): Promise<ProjectVisionVersion | undefined>;
  getCurrent(projectId: ProjectId): Promise<ProjectVisionVersion | undefined>;
  insert(entity: ProjectVisionVersion): Promise<void>;
}
export interface GoalRepository extends EntityRepository<Goal, GoalId> {
  listByProject(projectId: ProjectId): Promise<readonly Goal[]>;
}
export interface PlanRepository extends EntityRepository<Plan, PlanId> {
  listByProject(projectId: ProjectId): Promise<readonly Plan[]>;
}
export interface PlanRevisionRepository {
  getById(id: PlanRevisionId): Promise<PlanRevision | undefined>;
  getCurrent(planId: PlanId): Promise<PlanRevision | undefined>;
  insert(entity: PlanRevision): Promise<void>;
}
export interface TaskRepository extends EntityRepository<Task, TaskId> {
  listByProject(projectId: ProjectId): Promise<readonly Task[]>;
}
export interface FactoryRunRepository extends EntityRepository<FactoryRun, FactoryRunId> {
  listByProject(projectId: ProjectId): Promise<readonly FactoryRun[]>;
}
export interface AgentRunRepository extends EntityRepository<AgentRun, AgentRunId> {
  listByProject(projectId: ProjectId): Promise<readonly AgentRun[]>;
}
export type WorkspaceRepository = EntityRepository<Workspace, WorkspaceId>;
export interface AttemptRepository extends EntityRepository<Attempt, AttemptId> {
  listByAgentRunIds(agentRunIds: readonly AgentRunId[]): Promise<readonly Attempt[]>;
  bindProviderReference(attemptId: AttemptId, reference: ProviderReference): Promise<Attempt>;
}
export interface ChangeSetRepository extends EntityRepository<ChangeSet, ChangeSetId> {
  listByProject(projectId: ProjectId): Promise<readonly ChangeSet[]>;
}
export interface ReviewRepository extends EntityRepository<Review, ReviewId> {
  listByChangeSetIds(changeSetIds: readonly ChangeSetId[]): Promise<readonly Review[]>;
}
export interface VerificationEvidenceRepository extends EntityRepository<
  VerificationEvidence,
  VerificationEvidenceId
> {
  listByChangeSetIds(
    changeSetIds: readonly ChangeSetId[],
  ): Promise<readonly VerificationEvidence[]>;
}
export interface ReviewFindingRepository extends EntityRepository<ReviewFinding, ReviewFindingId> {
  listByChangeSetIds(changeSetIds: readonly ChangeSetId[]): Promise<readonly ReviewFinding[]>;
}

export interface CredentialAuthorityRepository {
  getByConnectionId(connectionId: ConnectionId): Promise<CredentialAuthority | undefined>;
  claim(input: {
    readonly connectionId: ConnectionId;
    readonly credentialReferenceId: CredentialReferenceId;
    readonly ownerId: PrincipalId;
  }): Promise<CredentialAuthority>;
  prepareHandoff(input: {
    readonly connectionId: ConnectionId;
    readonly credentialReferenceId: CredentialReferenceId;
    readonly ownerId: PrincipalId;
    readonly nextOwnerId: PrincipalId;
    readonly expectedGeneration: number;
  }): Promise<CredentialAuthority>;
  fence(input: {
    readonly connectionId: ConnectionId;
    readonly credentialReferenceId: CredentialReferenceId;
    readonly ownerId: PrincipalId;
    readonly expectedGeneration: number;
  }): Promise<CredentialAuthority>;
  transfer(input: {
    readonly connectionId: ConnectionId;
    readonly credentialReferenceId: CredentialReferenceId;
    readonly ownerId: PrincipalId;
    readonly nextOwnerId: PrincipalId;
    readonly expectedGeneration: number;
  }): Promise<CredentialAuthority>;
}

export interface BusinessEventRepository {
  append(event: BusinessEvent): Promise<void>;
}
export interface AuditRepository {
  append(record: AuditRecord): Promise<void>;
}
export interface OutboxMessage {
  readonly id: OutboxMessageId;
  readonly topic: string;
  readonly payload: unknown;
  readonly occurredAt: string;
}
export interface OutboxRepository {
  append(message: OutboxMessage): Promise<void>;
}

export interface ApplicationTransaction {
  readonly projects: ProjectRepository;
  readonly projectVisions: ProjectVisionRepository;
  readonly goals: GoalRepository;
  readonly plans: PlanRepository;
  readonly planRevisions: PlanRevisionRepository;
  readonly tasks: TaskRepository;
  readonly factoryRuns: FactoryRunRepository;
  readonly agentRuns: AgentRunRepository;
  readonly workspaces: WorkspaceRepository;
  readonly attempts: AttemptRepository;
  readonly changeSets: ChangeSetRepository;
  readonly reviews: ReviewRepository;
  readonly verificationEvidence: VerificationEvidenceRepository;
  readonly reviewFindings: ReviewFindingRepository;
  readonly credentialAuthorities: CredentialAuthorityRepository;
  readonly events: BusinessEventRepository;
  readonly audit: AuditRepository;
  readonly outbox: OutboxRepository;
}

export interface UnitOfWork {
  transaction<T>(work: (tx: ApplicationTransaction) => Promise<T>): Promise<T>;
}
