<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Persistence\Repositories;

use ApiModel\Domain\Repository\PayrollRepositoryInterface;
use PDO;

final class PdoPayrollRepository implements PayrollRepositoryInterface
{
    public function __construct(private readonly PDO $pdo) {}

    public function findById(string $id): ?array
    {
        $st = $this->pdo->prepare('SELECT * FROM hr.payrolls WHERE id = ? LIMIT 1');
        $st->execute([$id]);
        $row = $st->fetch();

        return $row !== false ? $row : null;
    }

    public function listByCompany(string $companyId): array
    {
        $st = $this->pdo->prepare(
            'SELECT * FROM hr.payrolls WHERE company_id = ? ORDER BY start_date DESC, created_at DESC'
        );
        $st->execute([$companyId]);

        return $st->fetchAll();
    }

    public function insert(array $payroll): void
    {
        $st = $this->pdo->prepare(
            'INSERT INTO hr.payrolls (
                id, company_id, name, start_date, end_date, total_earnings, total_deductions, total_net, status, journal_entry_id
             ) VALUES (
                :id, :company_id, :name, :start_date, :end_date, :total_earnings, :total_deductions, :total_net, :status, :journal_entry_id
             )'
        );
        $st->execute([
            'id' => $payroll['id'],
            'company_id' => $payroll['company_id'],
            'name' => $payroll['name'],
            'start_date' => $payroll['start_date'],
            'end_date' => $payroll['end_date'],
            'total_earnings' => $payroll['total_earnings'] ?? 0.0,
            'total_deductions' => $payroll['total_deductions'] ?? 0.0,
            'total_net' => $payroll['total_net'] ?? 0.0,
            'status' => $payroll['status'] ?: 'draft',
            'journal_entry_id' => $payroll['journal_entry_id'] ?: null,
        ]);
    }

    public function update(string $id, array $payroll): void
    {
        $st = $this->pdo->prepare(
            'UPDATE hr.payrolls SET
                name = :name,
                start_date = :start_date,
                end_date = :end_date,
                total_earnings = :total_earnings,
                total_deductions = :total_deductions,
                total_net = :total_net,
                status = :status,
                journal_entry_id = :journal_entry_id,
                updated_at = CURRENT_TIMESTAMP
             WHERE id = :id'
        );
        $st->execute([
            'id' => $id,
            'name' => $payroll['name'],
            'start_date' => $payroll['start_date'],
            'end_date' => $payroll['end_date'],
            'total_earnings' => $payroll['total_earnings'],
            'total_deductions' => $payroll['total_deductions'],
            'total_net' => $payroll['total_net'],
            'status' => $payroll['status'],
            'journal_entry_id' => $payroll['journal_entry_id'] ?: null,
        ]);
    }

    public function delete(string $id): void
    {
        $st = $this->pdo->prepare('DELETE FROM hr.payrolls WHERE id = ?');
        $st->execute([$id]);
    }

    public function findLinesByPayrollId(string $payrollId): array
    {
        $st = $this->pdo->prepare(
            'SELECT l.*, e.first_name, e.last_name, e.identification_number
             FROM hr.payroll_lines l
             JOIN hr.employees e ON l.employee_id = e.id
             WHERE l.payroll_id = ?
             ORDER BY e.first_name ASC, e.last_name ASC'
        );
        $st->execute([$payrollId]);

        return $st->fetchAll();
    }

    public function insertLines(string $payrollId, array $lines): void
    {
        $st = $this->pdo->prepare(
            'INSERT INTO hr.payroll_lines (
                id, payroll_id, employee_id, base_salary, bonuses, deductions, net_pay
             ) VALUES (
                ?, ?, ?, ?, ?, ?, ?
             )'
        );

        foreach ($lines as $line) {
            $id = $line['id'] ?: Database::uuid();
            $st->execute([
                $id,
                $payrollId,
                $line['employee_id'],
                $line['base_salary'],
                $line['bonuses'] ?? 0.0,
                $line['deductions'] ?? 0.0,
                $line['net_pay'],
            ]);
        }
    }

    public function deleteLines(string $payrollId): void
    {
        $st = $this->pdo->prepare('DELETE FROM hr.payroll_lines WHERE payroll_id = ?');
        $st->execute([$payrollId]);
    }

    public function updateStatus(string $id, string $status, ?string $journalEntryId): void
    {
        $st = $this->pdo->prepare('UPDATE hr.payrolls SET status = ?, journal_entry_id = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ?');
        $st->execute([$status, $journalEntryId, $id]);
    }
}
