/**
 * Result Lock Service
 *
 * Immutable result locking with super-admin-only unlock mechanism.
 * Creates point-in-time snapshots of deliberation results.
 */

import type { PrismaClient, CompetitionCategory, Prisma } from '@prisma/client'
import { logAudit } from '@/server/utils/audit'

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

export type LockResult = {
  success: boolean
  lock?: { id: string; lockedAt: Date }
  errors?: string[]
}

export type UnlockResult = {
  success: boolean
  event?: { id: string; unlockedAt: Date }
  errors?: string[]
}

export type LockStatus = {
  locked: boolean
  lock?: {
    id: string
    lockedAt: Date
    lockedBy: string
    resultSnapshot: unknown
  }
}

// ─── Lock Results ───────────────────────────────────────────────────────────

/**
 * Lock results for a competition/round/category combination.
 * Creates a ResultLock with a snapshot of deliberation results.
 */
export async function lockResults(
  params: {
    competitionId: string
    roundId: string
    category: CompetitionCategory
    lockedById: string
    resultSnapshot: unknown
  },
  prisma: PrismaClient,
): Promise<LockResult> {
  try {
    // Validate deliberation is finalized
    const session = await prisma.deliberationSession.findFirst({
      where: {
        competitionId: params.competitionId,
        roundId: params.roundId,
        category: params.category,
        status: 'DELIB_LOCKED',
      },
    })

    if (!session) {
      return {
        success: false,
        errors: ['No finalized deliberation session found for this competition/round/category'],
      }
    }

    // Check if already locked
    const existingLock = await prisma.resultLock.findFirst({
      where: {
        competitionId: params.competitionId,
        roundId: params.roundId,
        category: params.category,
      },
      include: { unlockEvents: true },
    })

    if (existingLock) {
      // If there are no unlock events, it's still locked
      const hasBeenUnlocked = existingLock.unlockEvents.length > 0
      if (!hasBeenUnlocked) {
        return { success: false, errors: ['Results are already locked'] }
      }
    }

    const lock = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
      const created = await tx.resultLock.create({
        data: {
          competitionId: params.competitionId,
          roundId: params.roundId,
          category: params.category,
          lockedById: params.lockedById,
          resultSnapshot: params.resultSnapshot as Prisma.InputJsonValue,
        },
      })

      await tx.decisionAuditLog.create({
        data: {
          eventType: 'results.locked',
          entityType: 'ResultLock',
          entityId: created.id,
          actorId: params.lockedById,
          detailsJson: {
            competitionId: params.competitionId,
            roundId: params.roundId,
            category: params.category,
          },
          snapshotJson: {
            timestamp: new Date().toISOString(),
            emittedBy: 'result-lock',
            resultSnapshot: params.resultSnapshot as Prisma.InputJsonValue,
          },
        },
      })

      await logAudit({
        prisma: tx,
        userId: params.lockedById,
        action: 'RESULTS_LOCK',
        entityType: 'ResultLock',
        entityId: created.id,
        detailsJson: {
          competitionId: params.competitionId,
          roundId: params.roundId,
          category: params.category,
        },
      })

      return created
    })

    return {
      success: true,
      lock: { id: lock.id, lockedAt: lock.lockedAt },
    }
  } catch (error) {
    console.error('[ResultLock] lockResults failed:', error)
    return {
      success: false,
      errors: [error instanceof Error ? error.message : 'Unknown error'],
    }
  }
}

// ─── Unlock Results ─────────────────────────────────────────────────────────

/**
 * Unlock results (super-admin only — enforced at router level).
 * Creates a ResultUnlockEvent with a required reason.
 */
export async function unlockResults(
  params: {
    resultLockId: string
    unlockedById: string
    reason: string
  },
  prisma: PrismaClient,
): Promise<UnlockResult> {
  try {
    const lock = await prisma.resultLock.findUnique({
      where: { id: params.resultLockId },
    })

    if (!lock) {
      return { success: false, errors: ['Result lock not found'] }
    }

    const event = await prisma.$transaction(async (tx: Prisma.TransactionClient) => {
      const created = await tx.resultUnlockEvent.create({
        data: {
          resultLockId: params.resultLockId,
          unlockedById: params.unlockedById,
          reason: params.reason,
        },
      })

      await tx.decisionAuditLog.create({
        data: {
          eventType: 'results.unlocked',
          entityType: 'ResultUnlockEvent',
          entityId: created.id,
          actorId: params.unlockedById,
          detailsJson: {
            resultLockId: params.resultLockId,
            reason: params.reason,
            competitionId: lock.competitionId,
            roundId: lock.roundId,
            category: lock.category,
          },
          snapshotJson: { timestamp: new Date().toISOString(), emittedBy: 'result-lock' },
        },
      })

      await logAudit({
        prisma: tx,
        userId: params.unlockedById,
        action: 'RESULTS_UNLOCK',
        entityType: 'ResultLock',
        entityId: params.resultLockId,
        detailsJson: { reason: params.reason },
      })

      return created
    })

    return {
      success: true,
      event: { id: event.id, unlockedAt: event.unlockedAt },
    }
  } catch (error) {
    console.error('[ResultLock] unlockResults failed:', error)
    return {
      success: false,
      errors: [error instanceof Error ? error.message : 'Unknown error'],
    }
  }
}

// ─── Query Helpers ──────────────────────────────────────────────────────────

/**
 * Check if results are locked for a competition/round/category.
 */
export async function isLocked(
  competitionId: string,
  roundId: string,
  category: CompetitionCategory,
  prisma: PrismaClient,
): Promise<LockStatus> {
  const lock = await prisma.resultLock.findFirst({
    where: { competitionId, roundId, category },
    include: {
      unlockEvents: { orderBy: { unlockedAt: 'desc' } },
      lockedBy: { select: { id: true, name: true, email: true } },
    },
    orderBy: { lockedAt: 'desc' },
  })

  if (!lock) {
    return { locked: false }
  }

  // If unlock events exist, the most recent action determines state
  // A lock is "unlocked" if there's at least one unlock event after the lock
  const hasBeenUnlocked = lock.unlockEvents.length > 0

  if (hasBeenUnlocked) {
    return { locked: false }
  }

  return {
    locked: true,
    lock: {
      id: lock.id,
      lockedAt: lock.lockedAt,
      lockedBy: lock.lockedBy.name ?? lock.lockedBy.email,
      resultSnapshot: lock.resultSnapshot,
    },
  }
}

/**
 * Get lock history for a competition.
 */
export async function getLockHistory(
  competitionId: string,
  prisma: PrismaClient,
) {
  return prisma.resultLock.findMany({
    where: { competitionId },
    include: {
      round: { select: { id: true, name: true, roundType: true } },
      lockedBy: { select: { id: true, name: true, email: true } },
      unlockEvents: {
        include: {
          unlockedBy: { select: { id: true, name: true, email: true } },
        },
        orderBy: { unlockedAt: 'desc' },
      },
    },
    orderBy: { lockedAt: 'desc' },
  })
}
