/**
 * Drizzle Errand Repository Adapter
 *
 * Implements ErrandRepository interface using Drizzle ORM.
 */

import { eq, and, desc } from 'drizzle-orm';
import { nanoid } from 'nanoid';
import type { DrizzleDatabase } from '../../index.js';
import { errands, agents, type Errand } from '../../schema.js';
import type {
  ErrandRepository,
  CreateErrandData,
  UpdateErrandData,
  ErrandWithAlias,
  FindAllErrandOptions,
} from '../errand-repository.js';

export class DrizzleErrandRepository implements ErrandRepository {
  constructor(private db: DrizzleDatabase) {}

  async create(data: CreateErrandData): Promise<Errand> {
    const now = new Date();
    const id = nanoid();
    const [created] = await this.db.insert(errands).values({
      id,
      description: data.description,
      branch: data.branch,
      baseBranch: data.baseBranch ?? 'main',
      agentId: data.agentId ?? null,
      projectId: data.projectId,
      status: data.status ?? 'active',
      conflictFiles: data.conflictFiles ?? null,
      createdAt: now,
      updatedAt: now,
    }).returning();
    return created;
  }

  async findById(id: string): Promise<ErrandWithAlias | null> {
    const rows = await this.db
      .select({
        id: errands.id,
        description: errands.description,
        branch: errands.branch,
        baseBranch: errands.baseBranch,
        agentId: errands.agentId,
        projectId: errands.projectId,
        status: errands.status,
        conflictFiles: errands.conflictFiles,
        createdAt: errands.createdAt,
        updatedAt: errands.updatedAt,
        agentAlias: agents.name,
      })
      .from(errands)
      .leftJoin(agents, eq(errands.agentId, agents.id))
      .where(eq(errands.id, id))
      .limit(1);
    if (!rows[0]) return null;
    return rows[0] as ErrandWithAlias;
  }

  async findAll(options?: FindAllErrandOptions): Promise<ErrandWithAlias[]> {
    const conditions = [];
    if (options?.projectId) conditions.push(eq(errands.projectId, options.projectId));
    if (options?.status) conditions.push(eq(errands.status, options.status));

    const rows = await this.db
      .select({
        id: errands.id,
        description: errands.description,
        branch: errands.branch,
        baseBranch: errands.baseBranch,
        agentId: errands.agentId,
        projectId: errands.projectId,
        status: errands.status,
        conflictFiles: errands.conflictFiles,
        createdAt: errands.createdAt,
        updatedAt: errands.updatedAt,
        agentAlias: agents.name,
      })
      .from(errands)
      .leftJoin(agents, eq(errands.agentId, agents.id))
      .where(conditions.length > 0 ? and(...conditions) : undefined)
      .orderBy(desc(errands.createdAt), desc(errands.id));
    return rows as ErrandWithAlias[];
  }

  async update(id: string, data: UpdateErrandData): Promise<Errand | null> {
    await this.db
      .update(errands)
      .set({ ...data, updatedAt: new Date() })
      .where(eq(errands.id, id));
    const rows = await this.db
      .select()
      .from(errands)
      .where(eq(errands.id, id))
      .limit(1);
    return rows[0] ?? null;
  }

  async delete(id: string): Promise<void> {
    await this.db.delete(errands).where(eq(errands.id, id));
  }
}
