/**
 * Document Comments and Annotations
 * Handles comments, annotations, and collaborative review features
 */

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

export const DocumentCommentSchema = z.object({
  id: z.string().uuid(),
  document_id: z.string().uuid(),
  version_id: z.string().uuid().optional(),
  parent_comment_id: z.string().uuid().optional(),
  comment_text: z.string(),
  comment_type: z.enum(['comment', 'suggestion', 'question', 'resolution']),
  status: z.enum(['open', 'resolved', 'dismissed']),
  page_number: z.number().int().optional(),
  x_position: z.number().optional(),
  y_position: z.number().optional(),
  highlight_text: z.string().optional(),
  author_id: z.string().uuid(),
  resolved_by: z.string().uuid().optional(),
  resolved_at: z.date().optional(),
  created_at: z.date(),
  updated_at: z.date(),
});

export type DocumentComment = z.infer<typeof DocumentCommentSchema>;

export interface CreateDocumentCommentInput {
  document_id: string;
  version_id?: string;
  parent_comment_id?: string;
  comment_text: string;
  comment_type?: 'comment' | 'suggestion' | 'question' | 'resolution';
  status?: 'open' | 'resolved' | 'dismissed';
  page_number?: number;
  x_position?: number;
  y_position?: number;
  highlight_text?: string;
  author_id: string;
}

/**
 * Create a document comment
 */
export async function createDocumentComment(
  input: CreateDocumentCommentInput
): Promise<DocumentComment> {
  const result = await query<DocumentComment>(
    `INSERT INTO document_comments 
     (document_id, version_id, parent_comment_id, comment_text, comment_type, 
      status, page_number, x_position, y_position, highlight_text, author_id)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
     RETURNING *`,
    [
      input.document_id,
      input.version_id || null,
      input.parent_comment_id || null,
      input.comment_text,
      input.comment_type || 'comment',
      input.status || 'open',
      input.page_number || null,
      input.x_position || null,
      input.y_position || null,
      input.highlight_text || null,
      input.author_id,
    ]
  );

  return result.rows[0]!;
}

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

/**
 * Get all comments for a document
 */
export async function getDocumentComments(
  document_id: string,
  version_id?: string,
  include_resolved = false
): Promise<DocumentComment[]> {
  const conditions = ['document_id = $1'];
  const params: unknown[] = [document_id];
  let paramIndex = 2;

  if (version_id) {
    conditions.push(`version_id = $${paramIndex++}`);
    params.push(version_id);
  }

  if (!include_resolved) {
    conditions.push(`status != 'resolved'`);
  }

  const result = await query<DocumentComment>(
    `SELECT * FROM document_comments 
     WHERE ${conditions.join(' AND ')}
     ORDER BY created_at ASC`,
    params
  );

  return result.rows;
}

/**
 * Get threaded comments (with replies)
 */
export interface ThreadedComment extends DocumentComment {
  replies?: ThreadedComment[];
}

export async function getThreadedDocumentComments(
  document_id: string,
  version_id?: string
): Promise<ThreadedComment[]> {
  const allComments = await getDocumentComments(document_id, version_id, true);

  // Build tree structure
  const commentMap = new Map<string, ThreadedComment>();
  const rootComments: ThreadedComment[] = [];

  // First pass: create map
  for (const comment of allComments) {
    commentMap.set(comment.id, { ...comment, replies: [] });
  }

  // Second pass: build tree
  for (const comment of allComments) {
    const threaded = commentMap.get(comment.id)!;
    if (comment.parent_comment_id) {
      const parent = commentMap.get(comment.parent_comment_id);
      if (parent) {
        parent.replies!.push(threaded);
      }
    } else {
      rootComments.push(threaded);
    }
  }

  return rootComments;
}

/**
 * Update comment
 */
export async function updateDocumentComment(
  id: string,
  updates: Partial<Pick<DocumentComment, 'comment_text' | 'status'>>
): Promise<DocumentComment | null> {
  const fields: string[] = [];
  const values: unknown[] = [];
  let paramIndex = 1;

  if (updates.comment_text !== undefined) {
    fields.push(`comment_text = $${paramIndex++}`);
    values.push(updates.comment_text);
  }

  if (updates.status !== undefined) {
    fields.push(`status = $${paramIndex++}`);
    values.push(updates.status);

    if (updates.status === 'resolved') {
      // Get current user from context - for now, we'll need to pass it
      // This should be handled by the service layer
    }
  }

  if (fields.length === 0) {
    return getDocumentComment(id);
  }

  fields.push(`updated_at = NOW()`);
  values.push(id);

  const result = await query<DocumentComment>(
    `UPDATE document_comments 
     SET ${fields.join(', ')}
     WHERE id = $${paramIndex}
     RETURNING *`,
    values
  );

  return result.rows[0] || null;
}

/**
 * Resolve comment
 */
export async function resolveDocumentComment(
  id: string,
  resolved_by: string
): Promise<DocumentComment | null> {
  const result = await query<DocumentComment>(
    `UPDATE document_comments 
     SET status = 'resolved', resolved_by = $1, resolved_at = NOW(), updated_at = NOW()
     WHERE id = $2
     RETURNING *`,
    [resolved_by, id]
  );

  return result.rows[0] || null;
}

/**
 * Get comment statistics for a document
 */
export interface CommentStatistics {
  total: number;
  open: number;
  resolved: number;
  dismissed: number;
  by_type: Record<string, number>;
}

export async function getDocumentCommentStatistics(
  document_id: string
): Promise<CommentStatistics> {
  const result = await query<{
    total: string;
    open: string;
    resolved: string;
    dismissed: string;
    comment_type: string;
    count: string;
  }>(
    `SELECT 
       COUNT(*) as total,
       COUNT(*) FILTER (WHERE status = 'open') as open,
       COUNT(*) FILTER (WHERE status = 'resolved') as resolved,
       COUNT(*) FILTER (WHERE status = 'dismissed') as dismissed,
       comment_type,
       COUNT(*) as count
     FROM document_comments
     WHERE document_id = $1
     GROUP BY comment_type`,
    [document_id]
  );

  const stats: CommentStatistics = {
    total: parseInt(result.rows[0]?.total || '0', 10),
    open: parseInt(result.rows[0]?.open || '0', 10),
    resolved: parseInt(result.rows[0]?.resolved || '0', 10),
    dismissed: parseInt(result.rows[0]?.dismissed || '0', 10),
    by_type: {},
  };

  for (const row of result.rows) {
    stats.by_type[row.comment_type] = parseInt(row.count, 10);
  }

  return stats;
}

