/**
 * Document Workflow Management
 * Handles approval, review, signing, and filing workflows
 */

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

export const DocumentWorkflowSchema = z.object({
  id: z.string().uuid(),
  document_id: z.string().uuid(),
  workflow_type: z.string(),
  status: z.enum(['pending', 'in_progress', 'completed', 'rejected', 'cancelled']),
  priority: z.enum(['low', 'normal', 'high', 'urgent']).optional(),
  initiated_by: z.string().uuid(),
  initiated_at: z.date(),
  completed_at: z.date().optional(),
  metadata: z.record(z.unknown()).optional(),
  created_at: z.date(),
  updated_at: z.date(),
});

export type DocumentWorkflow = z.infer<typeof DocumentWorkflowSchema>;

export const WorkflowStepSchema = z.object({
  id: z.string().uuid(),
  workflow_id: z.string().uuid(),
  step_number: z.number().int().positive(),
  step_type: z.string(),
  assigned_to: z.string().uuid().optional(),
  assigned_role: z.string().optional(),
  status: z.enum(['pending', 'in_progress', 'approved', 'rejected', 'skipped']),
  due_date: z.date().optional(),
  completed_at: z.date().optional(),
  comments: z.string().optional(),
  metadata: z.record(z.unknown()).optional(),
  created_at: z.date(),
  updated_at: z.date(),
});

export type WorkflowStep = z.infer<typeof WorkflowStepSchema>;

export type WorkflowType =
  | 'approval'
  | 'review'
  | 'signing'
  | 'filing'
  | 'publication'
  | 'custom';

export interface CreateDocumentWorkflowInput {
  document_id: string;
  workflow_type: WorkflowType;
  priority?: 'low' | 'normal' | 'high' | 'urgent';
  initiated_by: string;
  metadata?: Record<string, unknown>;
  steps?: CreateWorkflowStepInput[];
}

export interface CreateWorkflowStepInput {
  step_number: number;
  step_type: 'approval' | 'review' | 'signature' | 'notification';
  assigned_to?: string;
  assigned_role?: string;
  due_date?: Date | string;
  metadata?: Record<string, unknown>;
}

/**
 * Create a document workflow
 */
export async function createDocumentWorkflow(
  input: CreateDocumentWorkflowInput
): Promise<DocumentWorkflow> {
  const result = await query<DocumentWorkflow>(
    `INSERT INTO document_workflows 
     (document_id, workflow_type, status, priority, initiated_by, metadata)
     VALUES ($1, $2, $3, $4, $5, $6)
     RETURNING *`,
    [
      input.document_id,
      input.workflow_type,
      'pending',
      input.priority || 'normal',
      input.initiated_by,
      input.metadata ? JSON.stringify(input.metadata) : null,
    ]
  );

  const workflow = result.rows[0]!;

  // Create workflow steps if provided
  if (input.steps && input.steps.length > 0) {
    for (const step of input.steps) {
      await createWorkflowStep(workflow.id, step);
    }
  }

  return workflow;
}

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

/**
 * Get workflows for a document
 */
export async function getDocumentWorkflows(
  document_id: string,
  status?: string
): Promise<DocumentWorkflow[]> {
  const conditions = ['document_id = $1'];
  const params: unknown[] = [document_id];
  let paramIndex = 2;

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

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

  return result.rows;
}

/**
 * Update workflow status
 */
export async function updateWorkflowStatus(
  id: string,
  status: 'pending' | 'in_progress' | 'completed' | 'rejected' | 'cancelled'
): Promise<DocumentWorkflow | null> {
  const updates: string[] = [`status = $1`, `updated_at = NOW()`];
  const values: unknown[] = [status];

  if (status === 'completed' || status === 'rejected' || status === 'cancelled') {
    updates.push(`completed_at = NOW()`);
  }

  values.push(id);

  const result = await query<DocumentWorkflow>(
    `UPDATE document_workflows 
     SET ${updates.join(', ')}
     WHERE id = $${values.length}
     RETURNING *`,
    values
  );

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

/**
 * Create workflow step
 */
export async function createWorkflowStep(
  workflow_id: string,
  input: CreateWorkflowStepInput
): Promise<WorkflowStep> {
  const result = await query<WorkflowStep>(
    `INSERT INTO workflow_steps 
     (workflow_id, step_number, step_type, assigned_to, assigned_role, 
      status, due_date, metadata)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
     RETURNING *`,
    [
      workflow_id,
      input.step_number,
      input.step_type,
      input.assigned_to || null,
      input.assigned_role || null,
      'pending',
      input.due_date ? new Date(input.due_date) : null,
      input.metadata ? JSON.stringify(input.metadata) : null,
    ]
  );

  return result.rows[0]!;
}

/**
 * Get workflow steps
 */
export async function getWorkflowSteps(workflow_id: string): Promise<WorkflowStep[]> {
  const result = await query<WorkflowStep>(
    `SELECT * FROM workflow_steps 
     WHERE workflow_id = $1 
     ORDER BY step_number ASC`,
    [workflow_id]
  );
  return result.rows;
}

/**
 * Update workflow step status
 */
export async function updateWorkflowStepStatus(
  id: string,
  status: 'pending' | 'in_progress' | 'approved' | 'rejected' | 'skipped',
  comments?: string
): Promise<WorkflowStep | null> {
  const updates: string[] = [`status = $1`, `updated_at = NOW()`];
  const values: unknown[] = [status];

  if (status === 'approved' || status === 'rejected') {
    updates.push(`completed_at = NOW()`);
  }

  if (comments) {
    updates.push(`comments = $${values.length + 1}`);
    values.push(comments);
  }

  values.push(id);

  const result = await query<WorkflowStep>(
    `UPDATE workflow_steps 
     SET ${updates.join(', ')}
     WHERE id = $${values.length}
     RETURNING *`,
    values
  );

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

/**
 * Get pending workflows for a user
 */
export async function getPendingWorkflowsForUser(
  user_id: string,
  role?: string
): Promise<WorkflowStep[]> {
  const conditions = ['ws.status = $1'];
  const params: unknown[] = ['pending'];
  let paramIndex = 2;

  conditions.push(`(ws.assigned_to = $${paramIndex++} OR ws.assigned_role = $${paramIndex++})`);
  params.push(user_id);
  params.push(role || user_id); // Fallback to user_id if no role

  const result = await query<WorkflowStep>(
    `SELECT ws.*, dw.document_id, dw.workflow_type, dw.priority
     FROM workflow_steps ws
     JOIN document_workflows dw ON ws.workflow_id = dw.id
     WHERE ${conditions.join(' AND ')}
     ORDER BY dw.priority DESC, ws.due_date ASC NULLS LAST`,
    params
  );

  return result.rows;
}

/**
 * Get workflow progress
 */
export interface WorkflowProgress {
  workflow: DocumentWorkflow;
  steps: WorkflowStep[];
  completed_steps: number;
  total_steps: number;
  current_step?: WorkflowStep;
  progress_percentage: number;
}

export async function getWorkflowProgress(
  workflow_id: string
): Promise<WorkflowProgress | null> {
  const workflow = await getDocumentWorkflow(workflow_id);
  if (!workflow) {
    return null;
  }

  const steps = await getWorkflowSteps(workflow_id);
  const completed_steps = steps.filter(
    (s) => s.status === 'approved' || s.status === 'rejected' || s.status === 'skipped'
  ).length;

  const current_step = steps.find((s) => s.status === 'pending' || s.status === 'in_progress');

  return {
    workflow,
    steps,
    completed_steps,
    total_steps: steps.length,
    current_step,
    progress_percentage: steps.length > 0 ? (completed_steps / steps.length) * 100 : 0,
  };
}

// Aliases for route compatibility
export const listDocumentWorkflows = getDocumentWorkflows;
export const assignWorkflowStep = createWorkflowStep;
export async function completeWorkflowStep(
  step_id: string,
  status: 'approved' | 'rejected',
  comments?: string
): Promise<WorkflowStep | null> {
  return updateWorkflowStepStatus(step_id, status, comments);
}

