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

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

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

  async create(data: CreateErrandData): Promise<Errand> {
    const now = new Date();
    const [created] = await this.db
      .insert(errands)
      .values({ ...data, createdAt: now, updatedAt: now })
      .returning();
    return created;
  }

  async findById(id: string): Promise<ErrandWithAlias | undefined> {
    const result = 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,
        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);
    return result[0] ?? undefined;
  }

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

    return this.db
      .select({
        id: errands.id,
        description: errands.description,
        branch: errands.branch,
        baseBranch: errands.baseBranch,
        agentId: errands.agentId,
        projectId: errands.projectId,
        status: errands.status,
        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));
  }

  async update(id: string, data: UpdateErrandData): Promise<Errand> {
    const [updated] = await this.db
      .update(errands)
      .set({ ...data, updatedAt: new Date() })
      .where(eq(errands.id, id))
      .returning();
    if (!updated) throw new Error(`Errand not found: ${id}`);
    return updated;
  }

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