<?php

namespace App\Services;

use App\Models\Tenants\Salary;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;

class SalaryService extends Service
{
    /**
     * 급여 목록 조회
     */
    public function index(array $params): LengthAwarePaginator
    {
        $tenantId = $this->tenantId();

        $query = Salary::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'employee:id,name,user_id,email',
                'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
                'employeeProfile.department:id,name',
            ]);

        // 검색 필터 (직원명)
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->whereHas('employee', function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%");
            });
        }

        // 연도 필터
        if (! empty($params['year'])) {
            $query->where('year', $params['year']);
        }

        // 월 필터
        if (! empty($params['month'])) {
            $query->where('month', $params['month']);
        }

        // 상태 필터
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 기간 필터
        if (! empty($params['start_date']) && ! empty($params['end_date'])) {
            $query->whereBetween('payment_date', [$params['start_date'], $params['end_date']]);
        }

        // 직원 ID 필터
        if (! empty($params['employee_id'])) {
            $query->where('employee_id', $params['employee_id']);
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'year';
        $sortDir = $params['sort_dir'] ?? 'desc';

        if ($sortBy === 'year') {
            $query->orderBy('year', $sortDir)
                ->orderBy('month', $sortDir);
        } else {
            $query->orderBy($sortBy, $sortDir);
        }

        // 페이지네이션
        $perPage = $params['per_page'] ?? 20;

        return $query->paginate($perPage);
    }

    /**
     * 급여 상세 조회
     */
    public function show(int $id): Salary
    {
        $tenantId = $this->tenantId();

        return Salary::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'employee:id,name,user_id,email',
                'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
                'employeeProfile.department:id,name',
            ])
            ->findOrFail($id);
    }

    /**
     * 급여 등록
     */
    public function store(array $data): Salary
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($data, $tenantId, $userId) {
            $salary = new Salary;
            $salary->tenant_id = $tenantId;
            $salary->employee_id = $data['employee_id'];
            $salary->year = $data['year'];
            $salary->month = $data['month'];
            $salary->base_salary = $data['base_salary'] ?? 0;
            $salary->total_allowance = $data['total_allowance'] ?? 0;
            $salary->total_overtime = $data['total_overtime'] ?? 0;
            $salary->total_bonus = $data['total_bonus'] ?? 0;
            $salary->total_deduction = $data['total_deduction'] ?? 0;
            $salary->allowance_details = $data['allowance_details'] ?? null;
            $salary->deduction_details = $data['deduction_details'] ?? null;
            $salary->payment_date = $data['payment_date'] ?? null;
            $salary->status = $data['status'] ?? 'scheduled';
            $salary->created_by = $userId;
            $salary->updated_by = $userId;

            // 실지급액 계산
            $salary->net_payment = $salary->calculateNetPayment();

            $salary->save();

            return $salary->load('employee:id,name,email');
        });
    }

    /**
     * 급여 수정
     */
    public function update(int $id, array $data): Salary
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $data, $tenantId, $userId) {
            $salary = Salary::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            if (isset($data['employee_id'])) {
                $salary->employee_id = $data['employee_id'];
            }
            if (isset($data['year'])) {
                $salary->year = $data['year'];
            }
            if (isset($data['month'])) {
                $salary->month = $data['month'];
            }
            if (isset($data['base_salary'])) {
                $salary->base_salary = $data['base_salary'];
            }
            if (isset($data['total_allowance'])) {
                $salary->total_allowance = $data['total_allowance'];
            }
            if (isset($data['total_overtime'])) {
                $salary->total_overtime = $data['total_overtime'];
            }
            if (isset($data['total_bonus'])) {
                $salary->total_bonus = $data['total_bonus'];
            }
            if (isset($data['total_deduction'])) {
                $salary->total_deduction = $data['total_deduction'];
            }
            if (array_key_exists('allowance_details', $data)) {
                $salary->allowance_details = $data['allowance_details'];
            }
            if (array_key_exists('deduction_details', $data)) {
                $salary->deduction_details = $data['deduction_details'];
            }
            if (array_key_exists('payment_date', $data)) {
                $salary->payment_date = $data['payment_date'];
            }
            if (isset($data['status'])) {
                $salary->status = $data['status'];
            }

            // 실지급액 재계산
            $salary->net_payment = $salary->calculateNetPayment();

            $salary->updated_by = $userId;
            $salary->save();

            return $salary->fresh()->load([
                'employee:id,name,user_id,email',
                'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
                'employeeProfile.department:id,name',
            ]);
        });
    }

    /**
     * 급여 삭제
     */
    public function destroy(int $id): bool
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $tenantId, $userId) {
            $salary = Salary::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            $salary->deleted_by = $userId;
            $salary->save();
            $salary->delete();

            return true;
        });
    }

    /**
     * 급여 상태 변경 (지급완료/지급예정)
     */
    public function updateStatus(int $id, string $status): Salary
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($id, $status, $tenantId, $userId) {
            $salary = Salary::query()
                ->where('tenant_id', $tenantId)
                ->findOrFail($id);

            $salary->status = $status;
            $salary->updated_by = $userId;
            $salary->save();

            return $salary->load([
                'employee:id,name,user_id,email',
                'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
                'employeeProfile.department:id,name',
            ]);
        });
    }

    /**
     * 급여 일괄 상태 변경
     */
    public function bulkUpdateStatus(array $ids, string $status): int
    {
        $tenantId = $this->tenantId();
        $userId = $this->apiUserId();

        return DB::transaction(function () use ($ids, $status, $tenantId, $userId) {
            return Salary::query()
                ->where('tenant_id', $tenantId)
                ->whereIn('id', $ids)
                ->update([
                    'status' => $status,
                    'updated_by' => $userId,
                    'updated_at' => now(),
                ]);
        });
    }

    /**
     * 엑셀 내보내기용 데이터 조회
     *
     * @return array{data: array<int, array<string, mixed>>, headings: array<int, string>}
     */
    public function getExportData(array $params): array
    {
        $tenantId = $this->tenantId();

        $query = Salary::query()
            ->where('tenant_id', $tenantId)
            ->with([
                'employee:id,name,user_id,email',
                'employeeProfile' => fn ($q) => $q->where('tenant_id', $tenantId),
                'employeeProfile.department:id,name',
            ]);

        // 검색 필터 (직원명)
        if (! empty($params['search'])) {
            $search = $params['search'];
            $query->whereHas('employee', function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%");
            });
        }

        // 연도 필터
        if (! empty($params['year'])) {
            $query->where('year', $params['year']);
        }

        // 월 필터
        if (! empty($params['month'])) {
            $query->where('month', $params['month']);
        }

        // 상태 필터
        if (! empty($params['status'])) {
            $query->where('status', $params['status']);
        }

        // 기간 필터
        if (! empty($params['start_date']) && ! empty($params['end_date'])) {
            $query->whereBetween('payment_date', [$params['start_date'], $params['end_date']]);
        }

        // 직원 ID 필터
        if (! empty($params['employee_id'])) {
            $query->where('employee_id', $params['employee_id']);
        }

        // 정렬
        $sortBy = $params['sort_by'] ?? 'year';
        $sortDir = $params['sort_dir'] ?? 'desc';

        if ($sortBy === 'year') {
            $query->orderBy('year', $sortDir)
                ->orderBy('month', $sortDir);
        } else {
            $query->orderBy($sortBy, $sortDir);
        }

        $salaries = $query->get();

        // 상태 레이블 매핑
        $statusLabels = [
            'scheduled' => '지급예정',
            'completed' => '지급완료',
            'pending' => '보류',
        ];

        // 엑셀 데이터 변환
        $data = $salaries->map(function ($salary) use ($statusLabels) {
            return [
                $salary->year.'년 '.$salary->month.'월',
                $salary->employee?->name ?? '-',
                $salary->employeeProfile?->department?->name ?? '-',
                number_format($salary->base_salary),
                number_format($salary->total_allowance),
                number_format($salary->total_overtime),
                number_format($salary->total_bonus),
                number_format($salary->total_deduction),
                number_format($salary->net_payment),
                $statusLabels[$salary->status] ?? $salary->status,
                $salary->payment_date ?? '-',
            ];
        })->toArray();

        $headings = [
            '급여월',
            '직원명',
            '부서',
            '기본급',
            '수당',
            '야근수당',
            '상여금',
            '공제액',
            '실지급액',
            '상태',
            '지급일',
        ];

        return [
            'data' => $data,
            'headings' => $headings,
        ];
    }

    /**
     * 급여 통계 조회
     */
    public function getStatistics(array $params): array
    {
        $tenantId = $this->tenantId();

        $query = Salary::query()
            ->where('tenant_id', $tenantId);

        // 연도/월 필터
        if (! empty($params['year'])) {
            $query->where('year', $params['year']);
        }
        if (! empty($params['month'])) {
            $query->where('month', $params['month']);
        }

        // 기간 필터
        if (! empty($params['start_date']) && ! empty($params['end_date'])) {
            $query->whereBetween('payment_date', [$params['start_date'], $params['end_date']]);
        }

        return [
            'total_net_payment' => (float) $query->sum('net_payment'),
            'total_base_salary' => (float) $query->sum('base_salary'),
            'total_allowance' => (float) $query->sum('total_allowance'),
            'total_overtime' => (float) $query->sum('total_overtime'),
            'total_bonus' => (float) $query->sum('total_bonus'),
            'total_deduction' => (float) $query->sum('total_deduction'),
            'count' => $query->count(),
            'completed_count' => (clone $query)->where('status', 'completed')->count(),
            'scheduled_count' => (clone $query)->where('status', 'scheduled')->count(),
        ];
    }
}
