import { createScheduledDbService } from '@/server/services/db.js';
import { BaseDO } from './_base.js';
import type { MultidealEnv } from '../lib/env.js';
import { handleSupportTicketAlarm } from '../lifecycle/support-tickets.js';
import { insertOutboxRow } from '@/server/db/queries/outbox';

/**
 * SupportTicketDO — entity-alarm DO for support_tickets lifecycle.
 *
 * Stores ticketId on arm so alarm() can load the row.
 *
 * Key format: ticket:{uuid} (resolved via idFromName in do-client.ts).
 *
 * Two alarm scenarios:
 *   - status = 'resolved'     → autoclose → closed (arms at resolvedAt + autocloseDays)
 *   - status in active set    → SLA deadline passed → log + enqueue outbox
 */
export class SupportTicketDO extends BaseDO {
  protected override className = 'SupportTicketDO';
  constructor(ctx: DurableObjectState, env: MultidealEnv) {
    super(ctx, env);
  }

  override async alarm(): Promise<void> {
    const ticketId =
      (await this.ctx.storage.get<string>('ticket_id')) ??
      (await this.ctx.storage.get<string>('entity_id')) ??
      this.ctx.id.toString();

    const db = createScheduledDbService(this.env);

    const enqueueOutbox = async (kind: string, body: unknown) => {
      await insertOutboxRow(db as never, {
        aggregateType: 'ticket',
        aggregateId: ticketId,
        eventType: kind,
        payload: body as Record<string, unknown>,
      });
    };

    await handleSupportTicketAlarm({ db, enqueueOutbox }, ticketId);

    await this.ctx.storage.delete('arm_at');
    await this.ctx.storage.delete('arm_kind');
  }

  /**
   * Override fetch to capture ticketId from arm request body.
   */
  override async fetch(request: Request): Promise<Response> {
    const url = new URL(request.url);
    if (request.method === 'POST' && url.pathname === '/arm') {
      // Clone so base class can still read the body.
      const clone = request.clone();
      let body: { at?: number; ticketId?: string } = {};
      try {
        body = (await clone.json()) as typeof body;
      } catch (err) {
        void err;
        // fall through to base
      }
      if (body.ticketId) {
        await this.ctx.storage.put('ticket_id', body.ticketId);
      }
    }
    return super.fetch(request);
  }
}
