/**
 * @ai-summary Data access layer for ownership costs
 * @ai-context Handles database operations for vehicle ownership costs
 */

import { Pool } from 'pg';
import {
  OwnershipCost,
  CreateOwnershipCostRequest,
  UpdateOwnershipCostRequest,
  CostInterval,
  OwnershipCostType
} from '../domain/ownership-costs.types';

export class OwnershipCostsRepository {
  constructor(private pool: Pool) {}

  async create(data: CreateOwnershipCostRequest & { userId: string }): Promise<OwnershipCost> {
    const query = `
      INSERT INTO ownership_costs (
        user_id, vehicle_id, document_id, cost_type, description,
        amount, interval, start_date, end_date
      )
      VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
      RETURNING *
    `;

    const values = [
      data.userId,
      data.vehicleId,
      data.documentId ?? null,
      data.costType,
      data.description ?? null,
      data.amount,
      data.interval,
      data.startDate,
      data.endDate ?? null
    ];

    const result = await this.pool.query(query, values);
    return this.mapRow(result.rows[0]);
  }

  async findByVehicleId(vehicleId: string, userId: string): Promise<OwnershipCost[]> {
    const query = `
      SELECT * FROM ownership_costs
      WHERE vehicle_id = $1 AND user_id = $2
      ORDER BY start_date DESC, created_at DESC
    `;

    const result = await this.pool.query(query, [vehicleId, userId]);
    return result.rows.map(row => this.mapRow(row));
  }

  async findByUserId(userId: string): Promise<OwnershipCost[]> {
    const query = `
      SELECT * FROM ownership_costs
      WHERE user_id = $1
      ORDER BY start_date DESC, created_at DESC
    `;

    const result = await this.pool.query(query, [userId]);
    return result.rows.map(row => this.mapRow(row));
  }

  async findById(id: string): Promise<OwnershipCost | null> {
    const query = 'SELECT * FROM ownership_costs WHERE id = $1';
    const result = await this.pool.query(query, [id]);

    if (result.rows.length === 0) {
      return null;
    }

    return this.mapRow(result.rows[0]);
  }

  async findByDocumentId(documentId: string): Promise<OwnershipCost[]> {
    const query = `
      SELECT * FROM ownership_costs
      WHERE document_id = $1
      ORDER BY start_date DESC
    `;

    const result = await this.pool.query(query, [documentId]);
    return result.rows.map(row => this.mapRow(row));
  }

  async update(id: string, data: UpdateOwnershipCostRequest): Promise<OwnershipCost | null> {
    const fields = [];
    const values = [];
    let paramCount = 1;

    // Build dynamic update query
    if (data.documentId !== undefined) {
      fields.push(`document_id = $${paramCount++}`);
      values.push(data.documentId);
    }
    if (data.costType !== undefined) {
      fields.push(`cost_type = $${paramCount++}`);
      values.push(data.costType);
    }
    if (data.description !== undefined) {
      fields.push(`description = $${paramCount++}`);
      values.push(data.description);
    }
    if (data.amount !== undefined) {
      fields.push(`amount = $${paramCount++}`);
      values.push(data.amount);
    }
    if (data.interval !== undefined) {
      fields.push(`interval = $${paramCount++}`);
      values.push(data.interval);
    }
    if (data.startDate !== undefined) {
      fields.push(`start_date = $${paramCount++}`);
      values.push(data.startDate);
    }
    if (data.endDate !== undefined) {
      fields.push(`end_date = $${paramCount++}`);
      values.push(data.endDate);
    }

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

    values.push(id);
    const query = `
      UPDATE ownership_costs
      SET ${fields.join(', ')}
      WHERE id = $${paramCount}
      RETURNING *
    `;

    const result = await this.pool.query(query, values);

    if (result.rows.length === 0) {
      return null;
    }

    return this.mapRow(result.rows[0]);
  }

  async delete(id: string): Promise<boolean> {
    const query = 'DELETE FROM ownership_costs WHERE id = $1';
    const result = await this.pool.query(query, [id]);
    return (result.rowCount ?? 0) > 0;
  }

  async batchInsert(
    costs: Array<CreateOwnershipCostRequest & { userId: string }>,
    client?: Pool
  ): Promise<OwnershipCost[]> {
    if (costs.length === 0) {
      return [];
    }

    const queryClient = client || this.pool;
    const placeholders: string[] = [];
    const values: unknown[] = [];
    let paramCount = 1;

    costs.forEach((cost) => {
      const costParams = [
        cost.userId,
        cost.vehicleId,
        cost.documentId ?? null,
        cost.costType,
        cost.description ?? null,
        cost.amount,
        cost.interval,
        cost.startDate,
        cost.endDate ?? null
      ];

      const placeholder = `($${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++}, $${paramCount++})`;
      placeholders.push(placeholder);
      values.push(...costParams);
    });

    const query = `
      INSERT INTO ownership_costs (
        user_id, vehicle_id, document_id, cost_type, description,
        amount, interval, start_date, end_date
      )
      VALUES ${placeholders.join(', ')}
      RETURNING *
    `;

    const result = await queryClient.query(query, values);
    return result.rows.map((row: Record<string, unknown>) => this.mapRow(row));
  }

  private mapRow(row: Record<string, unknown>): OwnershipCost {
    return {
      id: row.id as string,
      userId: row.user_id as string,
      vehicleId: row.vehicle_id as string,
      documentId: row.document_id as string | undefined,
      costType: row.cost_type as OwnershipCostType,
      description: row.description as string | undefined,
      amount: Number(row.amount),
      interval: row.interval as CostInterval,
      startDate: row.start_date as Date,
      endDate: row.end_date as Date | undefined,
      createdAt: row.created_at as Date,
      updatedAt: row.updated_at as Date,
    };
  }
}
