<?php

namespace App\Services\Employee;

use App\Services\BaseService;
use App\Repositories\SalaryStructureRepository;
use App\Models\EmployeeSalaryStructure;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;

class SalaryStructureService extends BaseService
{
    protected SalaryStructureRepository $salaryStructureRepository;

    public function __construct(SalaryStructureRepository $repository)
    {
        parent::__construct($repository);
        $this->salaryStructureRepository = $repository;
    }

    /**
     * Get all with employee details
     */
    public function getAllWithEmployee(): Collection
    {
        return $this->salaryStructureRepository->getWithEmployee();
    }

    /**
     * Get active structures
     */
    public function getActive(): Collection
    {
        return $this->salaryStructureRepository->getActive();
    }

    /**
     * Get by employee
     */
    public function getByEmployee(int $employeeId): ?EmployeeSalaryStructure
    {
        return $this->salaryStructureRepository->getByEmployee($employeeId);
    }

    /**
     * Get active structure for employee
     */
    public function getActiveForEmployee(int $employeeId): ?EmployeeSalaryStructure
    {
        return $this->salaryStructureRepository->getActiveForEmployee($employeeId);
    }

    /**
     * Get currently effective structure for employee
     */
    public function getCurrentlyEffective(int $employeeId): ?EmployeeSalaryStructure
    {
        return $this->salaryStructureRepository->getCurrentlyEffective($employeeId);
    }

    /**
     * Get employees without salary structure
     */
    public function getEmployeesWithoutStructure(): Collection
    {
        return $this->salaryStructureRepository->getEmployeesWithoutStructure();
    }

    /**
     * Check if employee has salary structure
     */
    public function hasStructure(int $employeeId): bool
    {
        return $this->salaryStructureRepository->hasStructure($employeeId);
    }

    /**
     * Create salary structure for employee
     */
    public function createStructure(array $data): EmployeeSalaryStructure
    {
        return DB::transaction(function () use ($data) {
            // Deactivate existing structures for this employee
            if (!empty($data['employee_id'])) {
                $this->salaryStructureRepository->deactivateForEmployee($data['employee_id']);
            }

            // Set as active
            $data['status'] = EmployeeSalaryStructure::STATUS_ACTIVE;
            $data['effective_from'] = $data['effective_from'] ?? now()->toDateString();

            $this->logAction('Salary structure created', [
                'employee_id' => $data['employee_id'],
            ]);

            return $this->create($data);
        });
    }

    /**
     * Update salary structure
     */
    public function updateStructure(int $id, array $data): EmployeeSalaryStructure
    {
        return DB::transaction(function () use ($id, $data) {
            $this->logAction('Salary structure updated', ['id' => $id]);
            return $this->update($id, $data);
        });
    }

    /**
     * Revise salary structure (creates new, deactivates old)
     */
    public function reviseStructure(int $employeeId, array $data): EmployeeSalaryStructure
    {
        return DB::transaction(function () use ($employeeId, $data) {
            // Set effective_to on current structure
            $current = $this->getActiveForEmployee($employeeId);
            if ($current) {
                $current->update([
                    'effective_to' => now()->subDay()->toDateString(),
                    'status' => EmployeeSalaryStructure::STATUS_INACTIVE,
                ]);
            }

            // Create new structure
            $data['employee_id'] = $employeeId;
            $data['status'] = EmployeeSalaryStructure::STATUS_ACTIVE;
            $data['effective_from'] = now()->toDateString();

            $this->logAction('Salary structure revised', [
                'employee_id' => $employeeId,
                'previous_id' => $current?->id,
            ]);

            return $this->create($data);
        });
    }

    /**
     * Deactivate structure
     */
    public function deactivate(int $id): bool
    {
        return DB::transaction(function () use ($id) {
            $this->logAction('Salary structure deactivated', ['id' => $id]);
            return $this->salaryStructureRepository->deactivate($id);
        });
    }

    /**
     * Get salary breakdown for employee
     */
    public function getSalaryBreakdown(int $employeeId): ?array
    {
        $structure = $this->getCurrentlyEffective($employeeId);
        return $structure?->getSalaryBreakdown();
    }

    /**
     * Import salary structures from array
     */
    public function importStructures(array $structures): array
    {
        $results = ['success' => 0, 'failed' => 0, 'errors' => []];

        DB::transaction(function () use ($structures, &$results) {
            foreach ($structures as $index => $structure) {
                try {
                    $this->createStructure($structure);
                    $results['success']++;
                } catch (\Exception $e) {
                    $results['failed']++;
                    $results['errors'][] = "Row {$index}: {$e->getMessage()}";
                }
            }
        });

        return $results;
    }

    /**
     * Calculate salary for days worked
     */
    public function calculateSalaryForDays(int $employeeId, int $daysWorked, int $totalDaysInMonth): ?array
    {
        $structure = $this->getCurrentlyEffective($employeeId);
        if (!$structure) {
            return null;
        }

        $breakdown = $structure->getSalaryBreakdown();
        $ratio = $daysWorked / $totalDaysInMonth;

        return [
            'structure_id' => $structure->id,
            'days_worked' => $daysWorked,
            'total_days' => $totalDaysInMonth,
            'ratio' => $ratio,
            'calculated' => [
                'basic_da' => round($structure->basic_da * $ratio, 2),
                'hra' => round($structure->hra * $ratio, 2),
                'conveyance' => round($structure->conveyance * $ratio, 2),
                'washing_allowance' => round($structure->washing_allowance * $ratio, 2),
                'gross' => round($breakdown['earnings']['gross'] * $ratio, 2),
                'deductions' => round($breakdown['deductions']['total'] * $ratio, 2),
                'net' => round($breakdown['net_salary'] * $ratio, 2),
            ],
        ];
    }

    /**
     * Get summary statistics
     */
    public function getSummaryStats(): array
    {
        $active = $this->getActive();

        return [
            'total_structures' => $active->count(),
            'avg_basic_da' => round($active->avg('basic_da'), 2),
            'avg_gross' => round($active->map(fn($s) => $s->calculateGrossSalary())->avg(), 2),
            'avg_net' => round($active->map(fn($s) => $s->calculateNetSalary())->avg(), 2),
            'total_payroll_cost' => round($active->map(fn($s) => $s->calculateGrossSalary())->sum(), 2),
        ];
    }
}
