import { and, eq } from 'drizzle-orm';

import { db } from '@/lib/db';
import { interests } from '@/lib/db/schema/interests';
import { berths } from '@/lib/db/schema/berths';
import { systemSettings } from '@/lib/db/schema/system';
import { createAuditLog } from '@/lib/audit';
import { emitToRoom } from '@/lib/socket/server';

// ─── Types ────────────────────────────────────────────────────────────────────

export type BerthRuleTrigger =
  | 'eoi_sent'
  | 'eoi_signed'
  | 'deposit_received'
  | 'contract_signed'
  | 'interest_archived'
  | 'interest_completed'
  | 'berth_unlinked';

export type BerthRuleMode = 'auto' | 'suggest' | 'off';

export interface BerthRuleResult {
  action: 'applied' | 'suggested' | 'none';
  newStatus?: string;
  message?: string;
}

interface RuleConfig {
  mode: BerthRuleMode;
  targetStatus: string;
}

interface AuditMeta {
  userId: string;
  portId: string;
  ipAddress: string;
  userAgent: string;
}

// ─── Defaults ────────────────────────────────────────────────────────────────

const DEFAULT_RULES: Record<BerthRuleTrigger, RuleConfig> = {
  eoi_sent: { mode: 'suggest', targetStatus: 'under_offer' },
  eoi_signed: { mode: 'auto', targetStatus: 'under_offer' },
  deposit_received: { mode: 'auto', targetStatus: 'sold' },
  contract_signed: { mode: 'auto', targetStatus: 'sold' },
  interest_archived: { mode: 'suggest', targetStatus: 'available' },
  interest_completed: { mode: 'auto', targetStatus: 'sold' },
  berth_unlinked: { mode: 'off', targetStatus: 'available' },
};

// ─── Config ───────────────────────────────────────────────────────────────────

async function getRulesConfig(
  portId: string,
): Promise<Record<BerthRuleTrigger, RuleConfig>> {
  const setting = await db.query.systemSettings.findFirst({
    where: and(
      eq(systemSettings.key, 'berth_rules'),
      eq(systemSettings.portId, portId),
    ),
  });

  if (!setting?.value) {
    return { ...DEFAULT_RULES };
  }

  const stored = setting.value as Partial<Record<BerthRuleTrigger, RuleConfig>>;
  const merged = { ...DEFAULT_RULES };

  for (const trigger of Object.keys(DEFAULT_RULES) as BerthRuleTrigger[]) {
    if (stored[trigger]) {
      merged[trigger] = stored[trigger]!;
    }
  }

  return merged;
}

// ─── Evaluate Rule ────────────────────────────────────────────────────────────

export async function evaluateRule(
  trigger: BerthRuleTrigger,
  interestId: string,
  portId: string,
  meta: AuditMeta,
): Promise<BerthRuleResult> {
  const interest = await db.query.interests.findFirst({
    where: and(eq(interests.id, interestId), eq(interests.portId, portId)),
  });

  if (!interest?.berthId) {
    return { action: 'none' };
  }

  const rulesConfig = await getRulesConfig(portId);
  const rule = rulesConfig[trigger];

  if (rule.mode === 'off') {
    return { action: 'none' };
  }

  if (rule.mode === 'auto') {
    await db
      .update(berths)
      .set({
        status: rule.targetStatus,
        statusLastChangedBy: meta.userId,
        statusLastChangedReason: `Auto-applied by rule: ${trigger}`,
        statusLastModified: new Date(),
        updatedAt: new Date(),
      })
      .where(and(eq(berths.id, interest.berthId), eq(berths.portId, portId)));

    void createAuditLog({
      userId: meta.userId,
      portId,
      action: 'update',
      entityType: 'berth',
      entityId: interest.berthId,
      newValue: { status: rule.targetStatus },
      metadata: { type: 'berth_rule_auto', trigger, interestId },
      ipAddress: meta.ipAddress,
      userAgent: meta.userAgent,
    });

    emitToRoom(`port:${portId}`, 'berth:statusChanged', {
      berthId: interest.berthId,
      newStatus: rule.targetStatus,
      triggeredBy: meta.userId,
      trigger,
    });

    return { action: 'applied', newStatus: rule.targetStatus };
  }

  // suggest mode
  return {
    action: 'suggested',
    newStatus: rule.targetStatus,
    message: `Suggested status change to "${rule.targetStatus}" based on trigger "${trigger}"`,
  };
}
