/**
 * Legal Matter Management
 * Handles legal matters, cases, and matter-document relationships
 */

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

export const LegalMatterSchema = z.object({
  id: z.string().uuid(),
  matter_number: z.string(),
  title: z.string(),
  description: z.string().optional(),
  matter_type: z.string().optional(),
  status: z.enum(['open', 'closed', 'on_hold', 'archived']),
  priority: z.enum(['low', 'normal', 'high', 'urgent']).optional(),
  client_id: z.string().uuid().optional(),
  responsible_attorney_id: z.string().uuid().optional(),
  practice_area: z.string().optional(),
  jurisdiction: z.string().optional(),
  court_name: z.string().optional(),
  case_number: z.string().optional(),
  opened_date: z.date().optional(),
  closed_date: z.date().optional(),
  billing_code: z.string().optional(),
  metadata: z.record(z.unknown()).optional(),
  created_by: z.string().uuid().optional(),
  created_at: z.date(),
  updated_at: z.date(),
});

export type LegalMatter = z.infer<typeof LegalMatterSchema>;

export interface CreateLegalMatterInput {
  matter_number: string;
  title: string;
  description?: string;
  matter_type?: string;
  status?: 'open' | 'closed' | 'on_hold' | 'archived';
  priority?: 'low' | 'normal' | 'high' | 'urgent';
  client_id?: string;
  responsible_attorney_id?: string;
  practice_area?: string;
  jurisdiction?: string;
  court_name?: string;
  case_number?: string;
  opened_date?: Date | string;
  closed_date?: Date | string;
  billing_code?: string;
  metadata?: Record<string, unknown>;
  created_by?: string;
}

/**
 * Create a legal matter
 */
export async function createLegalMatter(input: CreateLegalMatterInput): Promise<LegalMatter> {
  const result = await query<LegalMatter>(
    `INSERT INTO legal_matters 
     (matter_number, title, description, matter_type, status, priority, 
      client_id, responsible_attorney_id, practice_area, jurisdiction, 
      court_name, case_number, opened_date, closed_date, billing_code, 
      metadata, created_by)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)
     RETURNING *`,
    [
      input.matter_number,
      input.title,
      input.description || null,
      input.matter_type || null,
      input.status || 'open',
      input.priority || 'normal',
      input.client_id || null,
      input.responsible_attorney_id || null,
      input.practice_area || null,
      input.jurisdiction || null,
      input.court_name || null,
      input.case_number || null,
      input.opened_date ? new Date(input.opened_date) : null,
      input.closed_date ? new Date(input.closed_date) : null,
      input.billing_code || null,
      input.metadata ? JSON.stringify(input.metadata) : null,
      input.created_by || null,
    ]
  );

  return result.rows[0]!;
}

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

/**
 * Get matter by matter number
 */
export async function getLegalMatterByNumber(
  matter_number: string
): Promise<LegalMatter | null> {
  const result = await query<LegalMatter>(
    `SELECT * FROM legal_matters WHERE matter_number = $1`,
    [matter_number]
  );
  return result.rows[0] || null;
}

/**
 * List matters with filters
 */
export interface MatterFilters {
  status?: string | string[];
  matter_type?: string;
  client_id?: string;
  responsible_attorney_id?: string;
  practice_area?: string;
  jurisdiction?: string;
  case_number?: string;
  search?: string;
}

export async function listLegalMatters(
  filters: MatterFilters = {},
  limit = 100,
  offset = 0
): Promise<LegalMatter[]> {
  const conditions: string[] = [];
  const params: unknown[] = [];
  let paramIndex = 1;

  if (filters.status) {
    if (Array.isArray(filters.status)) {
      conditions.push(`status = ANY($${paramIndex++})`);
      params.push(filters.status);
    } else {
      conditions.push(`status = $${paramIndex++}`);
      params.push(filters.status);
    }
  }

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

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

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

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

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

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

  if (filters.search) {
    conditions.push(
      `(matter_number ILIKE $${paramIndex} OR title ILIKE $${paramIndex} OR description ILIKE $${paramIndex})`
    );
    params.push(`%${filters.search}%`);
    paramIndex++;
  }

  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

  const result = await query<LegalMatter>(
    `SELECT * FROM legal_matters 
     ${whereClause}
     ORDER BY created_at DESC 
     LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
    [...params, limit, offset]
  );

  return result.rows;
}

/**
 * Update matter
 */
export async function updateLegalMatter(
  id: string,
  updates: Partial<
    Pick<
      LegalMatter,
      | 'title'
      | 'description'
      | 'status'
      | 'priority'
      | 'client_id'
      | 'responsible_attorney_id'
      | 'practice_area'
      | 'jurisdiction'
      | 'court_name'
      | 'case_number'
      | 'opened_date'
      | 'closed_date'
      | 'billing_code'
      | 'metadata'
    >
  >
): Promise<LegalMatter | null> {
  const fields: string[] = [];
  const values: unknown[] = [];
  let paramIndex = 1;

  const fieldMap: Record<string, string> = {
    title: 'title',
    description: 'description',
    status: 'status',
    priority: 'priority',
    client_id: 'client_id',
    responsible_attorney_id: 'responsible_attorney_id',
    practice_area: 'practice_area',
    jurisdiction: 'jurisdiction',
    court_name: 'court_name',
    case_number: 'case_number',
    opened_date: 'opened_date',
    closed_date: 'closed_date',
    billing_code: 'billing_code',
    metadata: 'metadata',
  };

  for (const [key, dbField] of Object.entries(fieldMap)) {
    if (key in updates && updates[key as keyof typeof updates] !== undefined) {
      const value = updates[key as keyof typeof updates];
      if (key === 'opened_date' || key === 'closed_date') {
        fields.push(`${dbField} = $${paramIndex++}`);
        values.push(value ? new Date(value as Date | string) : null);
      } else if (key === 'metadata') {
        fields.push(`${dbField} = $${paramIndex++}`);
        values.push(JSON.stringify(value));
      } else {
        fields.push(`${dbField} = $${paramIndex++}`);
        values.push(value);
      }
    }
  }

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

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

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

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

/**
 * Matter Participants
 */
export interface MatterParticipant {
  id: string;
  matter_id: string;
  user_id?: string;
  role: string;
  organization_name?: string;
  email?: string;
  phone?: string;
  is_primary: boolean;
  access_level: string;
  notes?: string;
  created_at: Date;
}

export async function addMatterParticipant(
  matter_id: string,
  participant: {
    user_id?: string;
    role: string;
    organization_name?: string;
    email?: string;
    phone?: string;
    is_primary?: boolean;
    access_level?: string;
    notes?: string;
  }
): Promise<MatterParticipant> {
  const result = await query<MatterParticipant>(
    `INSERT INTO matter_participants 
     (matter_id, user_id, role, organization_name, email, phone, 
      is_primary, access_level, notes)
     VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
     RETURNING *`,
    [
      matter_id,
      participant.user_id || null,
      participant.role,
      participant.organization_name || null,
      participant.email || null,
      participant.phone || null,
      participant.is_primary || false,
      participant.access_level || 'read',
      participant.notes || null,
    ]
  );

  return result.rows[0]!;
}

export async function getMatterParticipants(matter_id: string): Promise<MatterParticipant[]> {
  const result = await query<MatterParticipant>(
    `SELECT * FROM matter_participants 
     WHERE matter_id = $1 
     ORDER BY is_primary DESC, created_at ASC`,
    [matter_id]
  );
  return result.rows;
}

/**
 * Matter-Document Relationships
 */
export interface MatterDocument {
  id: string;
  matter_id: string;
  document_id: string;
  relationship_type: string;
  folder_path?: string;
  is_primary: boolean;
  display_order?: number;
  notes?: string;
  created_at: Date;
}

export async function linkDocumentToMatter(
  matter_id: string,
  document_id: string,
  relationship_type: string,
  options?: {
    folder_path?: string;
    is_primary?: boolean;
    display_order?: number;
    notes?: string;
  }
): Promise<MatterDocument> {
  const result = await query<MatterDocument>(
    `INSERT INTO matter_documents 
     (matter_id, document_id, relationship_type, folder_path, is_primary, display_order, notes)
     VALUES ($1, $2, $3, $4, $5, $6, $7)
     ON CONFLICT (matter_id, document_id) 
     DO UPDATE SET relationship_type = EXCLUDED.relationship_type,
                    folder_path = EXCLUDED.folder_path,
                    is_primary = EXCLUDED.is_primary,
                    display_order = EXCLUDED.display_order,
                    notes = EXCLUDED.notes
     RETURNING *`,
    [
      matter_id,
      document_id,
      relationship_type,
      options?.folder_path || null,
      options?.is_primary || false,
      options?.display_order || null,
      options?.notes || null,
    ]
  );

  return result.rows[0]!;
}

export async function getMatterDocuments(
  matter_id: string,
  relationship_type?: string
): Promise<MatterDocument[]> {
  const conditions = ['matter_id = $1'];
  const params: unknown[] = [matter_id];
  let paramIndex = 2;

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

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

  return result.rows;
}

export async function getDocumentMatters(document_id: string): Promise<MatterDocument[]> {
  const result = await query<MatterDocument>(
    `SELECT * FROM matter_documents 
     WHERE document_id = $1 
     ORDER BY created_at ASC`,
    [document_id]
  );
  return result.rows;
}

