import { Pool } from 'pg';
import pool from '../../../core/config/database';
import type { OwnershipCost, OwnershipCostType } from '../domain/ownership-costs.types';

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

  // ========================
  // Row Mappers
  // ========================

  private mapRow(row: any): OwnershipCost {
    return {
      id: row.id,
      userId: row.user_id,
      vehicleId: row.vehicle_id,
      documentId: row.document_id,
      costType: row.cost_type,
      amount: row.amount,
      description: row.description,
      periodStart: row.period_start,
      periodEnd: row.period_end,
      notes: row.notes,
      createdAt: row.created_at,
      updatedAt: row.updated_at
    };
  }

  // ========================
  // CRUD Operations
  // ========================

  async insert(cost: {
    id: string;
    userId: string;
    vehicleId: string;
    documentId?: string | null;
    costType: OwnershipCostType;
    amount: number;
    description?: string | null;
    periodStart?: string | null;
    periodEnd?: string | null;
    notes?: string | null;
  }): Promise<OwnershipCost> {
    const res = await this.db.query(
      `INSERT INTO ownership_costs (
        id, user_id, vehicle_id, document_id, cost_type, amount, description, period_start, period_end, notes
      ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
      RETURNING *`,
      [
        cost.id,
        cost.userId,
        cost.vehicleId,
        cost.documentId ?? null,
        cost.costType,
        cost.amount,
        cost.description ?? null,
        cost.periodStart ?? null,
        cost.periodEnd ?? null,
        cost.notes ?? null,
      ]
    );
    return this.mapRow(res.rows[0]);
  }

  async findById(id: string, userId: string): Promise<OwnershipCost | null> {
    const res = await this.db.query(
      `SELECT * FROM ownership_costs WHERE id = $1 AND user_id = $2`,
      [id, userId]
    );
    return res.rows[0] ? this.mapRow(res.rows[0]) : null;
  }

  async findByUserId(
    userId: string,
    filters?: { vehicleId?: string; costType?: OwnershipCostType; documentId?: string }
  ): Promise<OwnershipCost[]> {
    const conds: string[] = ['user_id = $1'];
    const params: any[] = [userId];
    let i = 2;

    if (filters?.vehicleId) {
      conds.push(`vehicle_id = $${i++}`);
      params.push(filters.vehicleId);
    }
    if (filters?.costType) {
      conds.push(`cost_type = $${i++}`);
      params.push(filters.costType);
    }
    if (filters?.documentId) {
      conds.push(`document_id = $${i++}`);
      params.push(filters.documentId);
    }

    const sql = `SELECT * FROM ownership_costs WHERE ${conds.join(' AND ')} ORDER BY period_start DESC, created_at DESC`;
    const res = await this.db.query(sql, params);
    return res.rows.map(row => this.mapRow(row));
  }

  async findByVehicleId(vehicleId: string, userId: string): Promise<OwnershipCost[]> {
    const res = await this.db.query(
      `SELECT * FROM ownership_costs WHERE vehicle_id = $1 AND user_id = $2 ORDER BY period_start DESC, created_at DESC`,
      [vehicleId, userId]
    );
    return res.rows.map(row => this.mapRow(row));
  }

  async update(
    id: string,
    userId: string,
    patch: Partial<Pick<OwnershipCost, 'documentId' | 'costType' | 'amount' | 'description' | 'periodStart' | 'periodEnd' | 'notes'>>
  ): Promise<OwnershipCost | null> {
    const fields: string[] = [];
    const params: any[] = [];
    let i = 1;

    if (patch.documentId !== undefined) {
      fields.push(`document_id = $${i++}`);
      params.push(patch.documentId);
    }
    if (patch.costType !== undefined) {
      fields.push(`cost_type = $${i++}`);
      params.push(patch.costType);
    }
    if (patch.amount !== undefined) {
      fields.push(`amount = $${i++}`);
      params.push(patch.amount);
    }
    if (patch.description !== undefined) {
      fields.push(`description = $${i++}`);
      params.push(patch.description);
    }
    if (patch.periodStart !== undefined) {
      fields.push(`period_start = $${i++}`);
      params.push(patch.periodStart);
    }
    if (patch.periodEnd !== undefined) {
      fields.push(`period_end = $${i++}`);
      params.push(patch.periodEnd);
    }
    if (patch.notes !== undefined) {
      fields.push(`notes = $${i++}`);
      params.push(patch.notes);
    }

    if (!fields.length) return this.findById(id, userId);

    params.push(id, userId);
    const sql = `UPDATE ownership_costs SET ${fields.join(', ')} WHERE id = $${i++} AND user_id = $${i++} RETURNING *`;
    const res = await this.db.query(sql, params);
    return res.rows[0] ? this.mapRow(res.rows[0]) : null;
  }

  async delete(id: string, userId: string): Promise<void> {
    await this.db.query(
      `DELETE FROM ownership_costs WHERE id = $1 AND user_id = $2`,
      [id, userId]
    );
  }
}
