import { and, eq, isNull } from 'drizzle-orm';
import type { DrizzleClient } from '@/server/db/client';
import { e2eFactoryCommands, e2eFactoryEntities } from '@/server/db/schema';
import type { FactoryStore } from './core';

export function createDbFactoryStore(db: DrizzleClient): FactoryStore {
  return {
    async claim(command, bodyHash) {
      const inserted = await db
        .insert(e2eFactoryCommands)
        .values({
          runId: command.runId,
          requestId: command.requestId,
          bodyHash,
          operation: command.operation,
        })
        .onConflictDoNothing()
        .returning({ requestId: e2eFactoryCommands.requestId });
      if (inserted.length === 1) return { status: 'claimed' };

      const [existing] = await db
        .select({
          bodyHash: e2eFactoryCommands.bodyHash,
          result: e2eFactoryCommands.result,
          completedAt: e2eFactoryCommands.completedAt,
        })
        .from(e2eFactoryCommands)
        .where(
          and(
            eq(e2eFactoryCommands.runId, command.runId),
            eq(e2eFactoryCommands.requestId, command.requestId),
          ),
        )
        .limit(1);
      if (!existing || existing.bodyHash !== bodyHash || !existing.completedAt) {
        return { status: 'conflict' };
      }
      return { status: 'replay', result: existing.result };
    },

    async complete(runId, requestId, result) {
      await db
        .update(e2eFactoryCommands)
        .set({ result, completedAt: new Date() })
        .where(
          and(eq(e2eFactoryCommands.runId, runId), eq(e2eFactoryCommands.requestId, requestId)),
        );
    },

    async register(entity) {
      await db.insert(e2eFactoryEntities).values(entity);
    },

    async findOwned(runId, kind, entityId) {
      const [entity] = await db
        .select()
        .from(e2eFactoryEntities)
        .where(
          and(
            eq(e2eFactoryEntities.runId, runId),
            eq(e2eFactoryEntities.kind, kind),
            eq(e2eFactoryEntities.entityId, entityId),
            isNull(e2eFactoryEntities.deletedAt),
          ),
        )
        .limit(1);
      return entity ?? null;
    },

    async listOwned(runId) {
      return db
        .select()
        .from(e2eFactoryEntities)
        .where(and(eq(e2eFactoryEntities.runId, runId), isNull(e2eFactoryEntities.deletedAt)));
    },

    async markDeleted(runId, kind, entityId) {
      await db
        .update(e2eFactoryEntities)
        .set({ deletedAt: new Date() })
        .where(
          and(
            eq(e2eFactoryEntities.runId, runId),
            eq(e2eFactoryEntities.kind, kind),
            eq(e2eFactoryEntities.entityId, entityId),
          ),
        );
    },
  };
}
