<?php

namespace App\Services\Leave;

use App\Models\LeaveType;
use App\Models\User;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class LeaveOpeningBalanceImportService
{
    /**
     * @return array{success: int, failed: int, errors: array<int, string>}
     */
    public function importFromCsv(UploadedFile $file, int $companyId, int $year, ?int $actorId = null): array
    {
        $path = $file->store('imports/leave-balances/' . $companyId, 'public');
        $fullPath = Storage::disk('public')->path($path);
        $handle = fopen($fullPath, 'r');
        if ($handle === false) {
            return ['success' => 0, 'failed' => 0, 'errors' => [1 => 'Could not read uploaded file.']];
        }

        $header = array_map(fn ($col) => strtolower(trim((string) $col)), fgetcsv($handle) ?: []);
        $success = 0;
        $failed = 0;
        $errors = [];
        $rowNumber = 1;
        $ledger = app(LeaveLedgerService::class);

        while (($line = fgetcsv($handle)) !== false) {
            $rowNumber++;
            $assoc = [];
            foreach ($header as $offset => $column) {
                if ($column !== '') {
                    $assoc[$column] = $line[$offset] ?? null;
                }
            }

            $validator = Validator::make($assoc, [
                'employee_number' => ['nullable', 'string', 'max:50'],
                'email' => ['nullable', 'email'],
                'leave_type' => ['required', 'string', 'max:191'],
                'opening_balance' => ['required', 'numeric', 'min:0'],
            ]);

            if ($validator->fails()) {
                $failed++;
                $errors[$rowNumber] = implode('; ', $validator->errors()->all());
                continue;
            }

            $data = $validator->validated();
            $userQuery = User::query()->forTenantDirectory()->where('company_id', $companyId);
            if (! empty($data['employee_number'])) {
                $userQuery->where('employee_number', $data['employee_number']);
            } elseif (! empty($data['email'])) {
                $userQuery->where('email', $data['email']);
            } else {
                $failed++;
                $errors[$rowNumber] = 'employee_number or email is required.';
                continue;
            }

            $user = $userQuery->first();
            if (! $user) {
                $failed++;
                $errors[$rowNumber] = 'Employee not found.';
                continue;
            }

            $leaveType = LeaveType::query()
                ->where('company_id', $companyId)
                ->where(function ($q) use ($data) {
                    $q->where('short_code', $data['leave_type'])
                        ->orWhere('name', $data['leave_type']);
                })
                ->first();

            if (! $leaveType) {
                $failed++;
                $errors[$rowNumber] = 'Leave type not found.';
                continue;
            }

            try {
                $ledger->creditOpeningBalance(
                    $user,
                    $leaveType,
                    $year,
                    (float) $data['opening_balance'],
                    $actorId,
                    'import:' . $year . ':user:' . $user->id . ':type:' . $leaveType->id,
                    true
                );
                $success++;
            } catch (\Throwable $e) {
                $failed++;
                $errors[$rowNumber] = $e->getMessage();
            }
        }

        fclose($handle);

        return compact('success', 'failed', 'errors');
    }

    /**
     * @return array<int, string>
     */
    public function templateHeaders(): array
    {
        return ['employee_number', 'email', 'leave_type', 'opening_balance'];
    }
}
