/**
 * Document Checkout/Lock Management
 * Prevents concurrent edits and manages document locks
 */

import { query } from './client';
import { z } from 'zod';

export const DocumentCheckoutSchema = z.object({
  id: z.string().uuid(),
  document_id: z.string().uuid(),
  checked_out_by: z.string().uuid(),
  checked_out_at: z.date(),
  expires_at: z.date(),
  lock_type: z.enum(['exclusive', 'shared_read']),
  notes: z.string().optional(),
});

export type DocumentCheckout = z.infer<typeof DocumentCheckoutSchema>;

export interface CreateCheckoutInput {
  document_id: string;
  checked_out_by: string;
  duration_hours?: number;
  lock_type?: 'exclusive' | 'shared_read';
  notes?: string;
}

/**
 * Check out a document (lock it for editing)
 */
export async function checkoutDocument(
  input: CreateCheckoutInput
): Promise<DocumentCheckout> {
  // Check if document is already checked out
  const existing = await getDocumentCheckout(input.document_id);
  if (existing) {
    if (existing.checked_out_by !== input.checked_out_by) {
      throw new Error('Document is already checked out by another user');
    }
    // Same user - extend checkout
    return extendCheckout(input.document_id, input.duration_hours || 24);
  }

  const duration_hours = input.duration_hours || 24;
  const expires_at = new Date();
  expires_at.setHours(expires_at.getHours() + duration_hours);

  const result = await query<DocumentCheckout>(
    `INSERT INTO document_checkouts 
     (document_id, checked_out_by, expires_at, lock_type, notes)
     VALUES ($1, $2, $3, $4, $5)
     RETURNING *`,
    [
      input.document_id,
      input.checked_out_by,
      expires_at,
      input.lock_type || 'exclusive',
      input.notes || null,
    ]
  );

  // Update document table
  await query(
    `UPDATE documents 
     SET is_checked_out = TRUE, checked_out_by = $1, checked_out_at = NOW()
     WHERE id = $2`,
    [input.checked_out_by, input.document_id]
  );

  return result.rows[0]!;
}

/**
 * Check in a document (release the lock)
 */
export async function checkinDocument(
  document_id: string,
  checked_out_by: string
): Promise<boolean> {
  const checkout = await getDocumentCheckout(document_id);
  if (!checkout) {
    return false; // Not checked out
  }

  if (checkout.checked_out_by !== checked_out_by) {
    throw new Error('Document is checked out by another user');
  }

  await query(
    `DELETE FROM document_checkouts WHERE document_id = $1`,
    [document_id]
  );

  // Update document table
  await query(
    `UPDATE documents 
     SET is_checked_out = FALSE, checked_out_by = NULL, checked_out_at = NULL
     WHERE id = $1`,
    [document_id]
  );

  return true;
}

/**
 * Get checkout status for a document
 */
export async function getDocumentCheckout(
  document_id: string
): Promise<DocumentCheckout | null> {
  // Clean up expired checkouts first
  await cleanupExpiredCheckouts();

  const result = await query<DocumentCheckout>(
    `SELECT * FROM document_checkouts 
     WHERE document_id = $1 AND expires_at > NOW()`,
    [document_id]
  );
  return result.rows[0] || null;
}

/**
 * Extend checkout duration
 */
export async function extendCheckout(
  document_id: string,
  additional_hours: number
): Promise<DocumentCheckout> {
  const result = await query<DocumentCheckout>(
    `UPDATE document_checkouts 
     SET expires_at = expires_at + INTERVAL '${additional_hours} hours'
     WHERE document_id = $1
     RETURNING *`,
    [document_id]
  );

  if (result.rows.length === 0) {
    throw new Error('Document is not checked out');
  }

  return result.rows[0]!;
}

/**
 * Force release checkout (admin function)
 */
export async function forceReleaseCheckout(document_id: string): Promise<boolean> {
  await query(`DELETE FROM document_checkouts WHERE document_id = $1`, [document_id]);

  await query(
    `UPDATE documents 
     SET is_checked_out = FALSE, checked_out_by = NULL, checked_out_at = NULL
     WHERE id = $1`,
    [document_id]
  );

  return true;
}

/**
 * Clean up expired checkouts
 */
export async function cleanupExpiredCheckouts(): Promise<number> {
  const result = await query<{ count: string }>(
    `SELECT COUNT(*) as count 
     FROM document_checkouts 
     WHERE expires_at <= NOW()`
  );
  const expiredCount = parseInt(result.rows[0]?.count || '0', 10);

  if (expiredCount > 0) {
    await query(
      `DELETE FROM document_checkouts WHERE expires_at <= NOW()`
    );

    // Update documents table
    await query(
      `UPDATE documents 
       SET is_checked_out = FALSE, checked_out_by = NULL, checked_out_at = NULL
       WHERE id IN (
         SELECT document_id FROM document_checkouts WHERE expires_at <= NOW()
       )`
    );
  }

  return expiredCount;
}

/**
 * Get all checkouts for a user
 */
export async function getUserCheckouts(user_id: string): Promise<DocumentCheckout[]> {
  await cleanupExpiredCheckouts();

  const result = await query<DocumentCheckout>(
    `SELECT * FROM document_checkouts 
     WHERE checked_out_by = $1 AND expires_at > NOW()
     ORDER BY expires_at ASC`,
    [user_id]
  );
  return result.rows;
}

/**
 * Get all active checkouts
 */
export async function getAllActiveCheckouts(): Promise<DocumentCheckout[]> {
  await cleanupExpiredCheckouts();

  const result = await query<DocumentCheckout>(
    `SELECT * FROM document_checkouts 
     WHERE expires_at > NOW()
     ORDER BY expires_at ASC`
  );
  return result.rows;
}

