/**
 * Contract settings query helpers — settings-contracts (wave-13, P165).
 *
 * Reads and writes contract-config columns from tenant_settings.
 * Routes MUST NOT import raw Drizzle tables — they call these helpers.
 */
import { eq, sql } from 'drizzle-orm'
import type { Db } from '../client'
import { tenantSettings } from '../schema/tenants'
import { auditLog } from './_audit-forward'
import type { ContractSettings, UpdateContractSettingsInput } from '@zync/types'

// ── CONTRACT_SETTINGS_DEFAULTS ────────────────────────────────────────────────

const CONTRACT_SETTINGS_DEFAULTS: ContractSettings = {
  contract_default_template_id: null,
  contract_default_expiry_days: 365,
  contract_default_signing_order: 'parallel',
  contract_require_email_verification: true,
  contract_reminder_first_days: 3,
  contract_reminder_followup_days: 7,
  contract_reminder_max_count: 3,
  contract_renewal_remind_30d: true,
  contract_renewal_remind_7d: true,
  contract_renewal_remind_1d: false,
  contract_renewal_notify_email: true,
  contract_renewal_notify_in_app: true,
}

// ── Helpers ───────────────────────────────────────────────────────────────────

function rowToContractSettings(row: typeof tenantSettings.$inferSelect): ContractSettings {
  return {
    contract_default_template_id: row.contractDefaultTemplateId ?? null,
    contract_default_expiry_days: row.contractDefaultExpiryDays,
    contract_default_signing_order: (row.contractDefaultSigningOrder ?? 'parallel') as 'parallel' | 'ordered',
    contract_require_email_verification: row.contractRequireEmailVerification,
    contract_reminder_first_days: row.contractReminderFirstDays,
    contract_reminder_followup_days: row.contractReminderFollowupDays,
    contract_reminder_max_count: row.contractReminderMaxCount,
    contract_renewal_remind_30d: row.contractRenewalRemind30d,
    contract_renewal_remind_7d: row.contractRenewalRemind7d,
    contract_renewal_remind_1d: row.contractRenewalRemind1d,
    contract_renewal_notify_email: row.contractRenewalNotifyEmail,
    contract_renewal_notify_in_app: row.contractRenewalNotifyInApp,
  }
}

// ── getContractSettings ───────────────────────────────────────────────────────

export async function getContractSettings(
  db: Db,
  tenantId: string,
): Promise<ContractSettings> {
  const rows = await db
    .select()
    .from(tenantSettings)
    .where(eq(tenantSettings.tenantId, tenantId))
    .limit(1)

  const row = rows[0]
  if (!row) {
    return { ...CONTRACT_SETTINGS_DEFAULTS }
  }

  return rowToContractSettings(row)
}

// ── updateContractSettings ────────────────────────────────────────────────────

export class CrossTenantTemplateError extends Error {
  constructor() {
    super('contract_default_template_id does not belong to this tenant')
    this.name = 'CrossTenantTemplateError'
  }
}

export async function updateContractSettings(
  db: Db,
  tenantId: string,
  actorId: string,
  patch: UpdateContractSettingsInput,
): Promise<ContractSettings> {
  // Validate cross-tenant template ownership when a non-null template id is supplied
  if (patch.contract_default_template_id != null) {
    const result = await db.execute(
      sql`SELECT tenant_id FROM contract_templates WHERE id = ${patch.contract_default_template_id} LIMIT 1`,
    )
    const templateRow = result[0] as { tenant_id: string } | undefined
    if (!templateRow || templateRow.tenant_id !== tenantId) {
      throw new CrossTenantTemplateError()
    }
  }

  await db.transaction(async (tx) => {
    await tx
      .update(tenantSettings)
      .set({
        ...(patch.contract_default_template_id !== undefined && {
          contractDefaultTemplateId: patch.contract_default_template_id,
        }),
        ...(patch.contract_default_expiry_days !== undefined && {
          contractDefaultExpiryDays: patch.contract_default_expiry_days,
        }),
        ...(patch.contract_default_signing_order !== undefined && {
          contractDefaultSigningOrder: patch.contract_default_signing_order,
        }),
        ...(patch.contract_require_email_verification !== undefined && {
          contractRequireEmailVerification: patch.contract_require_email_verification,
        }),
        ...(patch.contract_reminder_first_days !== undefined && {
          contractReminderFirstDays: patch.contract_reminder_first_days,
        }),
        ...(patch.contract_reminder_followup_days !== undefined && {
          contractReminderFollowupDays: patch.contract_reminder_followup_days,
        }),
        ...(patch.contract_reminder_max_count !== undefined && {
          contractReminderMaxCount: patch.contract_reminder_max_count,
        }),
        ...(patch.contract_renewal_remind_30d !== undefined && {
          contractRenewalRemind30d: patch.contract_renewal_remind_30d,
        }),
        ...(patch.contract_renewal_remind_7d !== undefined && {
          contractRenewalRemind7d: patch.contract_renewal_remind_7d,
        }),
        ...(patch.contract_renewal_remind_1d !== undefined && {
          contractRenewalRemind1d: patch.contract_renewal_remind_1d,
        }),
        ...(patch.contract_renewal_notify_email !== undefined && {
          contractRenewalNotifyEmail: patch.contract_renewal_notify_email,
        }),
        ...(patch.contract_renewal_notify_in_app !== undefined && {
          contractRenewalNotifyInApp: patch.contract_renewal_notify_in_app,
        }),
        updatedAt: new Date(),
      })
      .where(eq(tenantSettings.tenantId, tenantId))

    await tx.insert(auditLog).values({
      tenantId,
      actorId,
      actorType: 'user',
      entityType: 'contract_settings',
      entityId: tenantId,
      action: 'update',
      changes: null,
    })
  })

  return getContractSettings(db, tenantId)
}
