/**
 * Document Version Management
 * Handles document versioning, revision history, and version control
 */

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

export const DocumentVersionSchema = z.object({
  id: z.string().uuid(),
  document_id: z.string().uuid(),
  version_number: z.number().int().positive(),
  version_label: z.string().optional(),
  content: z.string().optional(),
  file_url: z.string().url().optional(),
  file_hash: z.string().optional(),
  file_size: z.number().int().nonnegative().optional(),
  mime_type: z.string().optional(),
  change_summary: z.string().optional(),
  change_type: z.enum(['created', 'modified', 'restored', 'merged']),
  created_by: z.string().uuid().optional(),
  created_at: z.date(),
});

export type DocumentVersion = z.infer<typeof DocumentVersionSchema>;

export interface CreateDocumentVersionInput {
  document_id: string;
  version_number?: number;
  version_label?: string;
  content?: string;
  file_url?: string;
  file_hash?: string;
  file_size?: number;
  mime_type?: string;
  change_summary?: string;
  change_type?: 'created' | 'modified' | 'restored' | 'merged';
  created_by?: string;
}

/**
 * Create a new document version
 */
export async function createDocumentVersion(
  input: CreateDocumentVersionInput
): Promise<DocumentVersion> {
  // Get next version number if not provided
  let version_number = input.version_number;
  if (!version_number) {
    const maxVersion = await query<{ max_version: number | null }>(
      `SELECT MAX(version_number) as max_version 
       FROM document_versions 
       WHERE document_id = $1`,
      [input.document_id]
    );
    version_number = (maxVersion.rows[0]?.max_version || 0) + 1;
  }

  const result = await query<DocumentVersion>(
    `INSERT INTO document_versions 
     (document_id, version_number, version_label, content, file_url, file_hash, 
      file_size, mime_type, change_summary, change_type, created_by)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
     RETURNING *`,
    [
      input.document_id,
      version_number,
      input.version_label || null,
      input.content || null,
      input.file_url || null,
      input.file_hash || null,
      input.file_size || null,
      input.mime_type || null,
      input.change_summary || null,
      input.change_type || 'modified',
      input.created_by || null,
    ]
  );

  const version = result.rows[0]!;

  // Update document's current version
  await query(
    `UPDATE documents 
     SET current_version = $1, latest_version_id = $2, updated_at = NOW()
     WHERE id = $3`,
    [version_number, version.id, input.document_id]
  );

  return version;
}

/**
 * Get document version by ID
 */
export async function getDocumentVersion(id: string): Promise<DocumentVersion | null> {
  const result = await query<DocumentVersion>(
    `SELECT * FROM document_versions WHERE id = $1`,
    [id]
  );
  return result.rows[0] || null;
}

/**
 * Get all versions for a document
 */
export async function getDocumentVersions(
  document_id: string,
  limit = 100,
  offset = 0
): Promise<DocumentVersion[]> {
  const result = await query<DocumentVersion>(
    `SELECT * FROM document_versions 
     WHERE document_id = $1 
     ORDER BY version_number DESC 
     LIMIT $2 OFFSET $3`,
    [document_id, limit, offset]
  );
  return result.rows;
}

/**
 * Get specific version by number
 */
export async function getDocumentVersionByNumber(
  document_id: string,
  version_number: number
): Promise<DocumentVersion | null> {
  const result = await query<DocumentVersion>(
    `SELECT * FROM document_versions 
     WHERE document_id = $1 AND version_number = $2`,
    [document_id, version_number]
  );
  return result.rows[0] || null;
}

/**
 * Get latest version of a document
 */
export async function getLatestDocumentVersion(
  document_id: string
): Promise<DocumentVersion | null> {
  const result = await query<DocumentVersion>(
    `SELECT * FROM document_versions 
     WHERE document_id = $1 
     ORDER BY version_number DESC 
     LIMIT 1`,
    [document_id]
  );
  return result.rows[0] || null;
}

/**
 * Compare two document versions
 */
export interface VersionComparison {
  version1: DocumentVersion;
  version2: DocumentVersion;
  differences: {
    field: string;
    old_value: unknown;
    new_value: unknown;
  }[];
}

export async function compareDocumentVersions(
  version1_id: string,
  version2_id: string
): Promise<VersionComparison | null> {
  const v1 = await getDocumentVersion(version1_id);
  const v2 = await getDocumentVersion(version2_id);

  if (!v1 || !v2) {
    return null;
  }

  const differences: VersionComparison['differences'] = [];

  if (v1.content !== v2.content) {
    differences.push({
      field: 'content',
      old_value: v1.content,
      new_value: v2.content,
    });
  }

  if (v1.file_url !== v2.file_url) {
    differences.push({
      field: 'file_url',
      old_value: v1.file_url,
      new_value: v2.file_url,
    });
  }

  if (v1.file_hash !== v2.file_hash) {
    differences.push({
      field: 'file_hash',
      old_value: v1.file_hash,
      new_value: v2.file_hash,
    });
  }

  if (v1.change_summary !== v2.change_summary) {
    differences.push({
      field: 'change_summary',
      old_value: v1.change_summary,
      new_value: v2.change_summary,
    });
  }

  return {
    version1: v1,
    version2: v2,
    differences,
  };
}

/**
 * Restore a document to a previous version
 */
export async function restoreDocumentVersion(
  document_id: string,
  version_id: string,
  restored_by: string,
  change_summary?: string
): Promise<DocumentVersion> {
  const targetVersion = await getDocumentVersion(version_id);
  if (!targetVersion || targetVersion.document_id !== document_id) {
    throw new Error('Version not found or does not belong to document');
  }

  // Create new version from the restored one
  return createDocumentVersion({
    document_id,
    version_label: `Restored from v${targetVersion.version_number}`,
    content: targetVersion.content,
    file_url: targetVersion.file_url,
    file_hash: targetVersion.file_hash,
    file_size: targetVersion.file_size,
    mime_type: targetVersion.mime_type,
    change_summary: change_summary || `Restored from version ${targetVersion.version_number}`,
    change_type: 'restored',
    created_by: restored_by,
  });
}

/**
 * Get version history with change summaries
 */
export interface VersionHistoryEntry extends DocumentVersion {
  created_by_name?: string;
  created_by_email?: string;
}

export async function getDocumentVersionHistory(
  document_id: string
): Promise<VersionHistoryEntry[]> {
  const result = await query<VersionHistoryEntry>(
    `SELECT dv.*, u.name as created_by_name, u.email as created_by_email
     FROM document_versions dv
     LEFT JOIN users u ON dv.created_by = u.id
     WHERE dv.document_id = $1
     ORDER BY dv.version_number DESC`,
    [document_id]
  );
  return result.rows;
}

