<?php

namespace App\Services;

use App\Models\AssetType;
use App\Models\Company;
use App\Models\Department;
use App\Models\Designation;
use App\Models\LeaveType;
use App\Models\SalaryGroup;
use App\Models\Shift;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class CompanySetupService
{
    public function initializeDefaults(Company $company): void
    {
        DB::transaction(function () use ($company): void {
            $freshCompany = Company::query()
                ->whereKey($company->id)
                ->lockForUpdate()
                ->first();

            if (! $freshCompany || $freshCompany->is_initialized) {
                return;
            }

            $companyId = (int) $freshCompany->id;
            $defaults = config('hrms_defaults', []);

            foreach (($defaults['departments'] ?? []) as $name) {
                Department::withoutGlobalScopes()->firstOrCreate([
                    'company_id' => $companyId,
                    'name' => (string) $name,
                ]);
            }

            foreach (($defaults['designations'] ?? []) as $name) {
                Designation::withoutGlobalScopes()->firstOrCreate([
                    'company_id' => $companyId,
                    'name' => (string) $name,
                ]);
            }

            foreach (($defaults['shifts'] ?? []) as $shift) {
                Shift::withoutGlobalScopes()->firstOrCreate(
                    [
                        'company_id' => $companyId,
                        'name' => (string) ($shift['name'] ?? ''),
                    ],
                    [
                        'clock_in_time' => (string) ($shift['start'] ?? '09:00'),
                        'clock_out_time' => (string) ($shift['end'] ?? '18:00'),
                    ]
                );
            }

            foreach (($defaults['leave_types'] ?? []) as $leaveType) {
                $name = (string) ($leaveType['name'] ?? '');
                $days = (int) ($leaveType['days'] ?? 0);

                LeaveType::withoutGlobalScopes()->firstOrCreate(
                    [
                        'company_id' => $companyId,
                        'name' => $name,
                    ],
                    [
                        'short_code' => $this->makeLeaveShortCode($name),
                        'is_paid' => Str::contains(Str::lower($name), 'paid'),
                        'total_leaves' => $days,
                        'leave_count' => $days,
                        'count_type' => 'same_for_all',
                    ]
                );
            }

            foreach (($defaults['asset_types'] ?? []) as $name) {
                AssetType::withoutGlobalScopes()->firstOrCreate([
                    'company_id' => $companyId,
                    'name' => (string) $name,
                ]);
            }

            foreach (($defaults['salary_groups'] ?? []) as $name) {
                SalaryGroup::withoutGlobalScopes()->firstOrCreate([
                    'company_id' => $companyId,
                    'name' => (string) $name,
                ]);
            }

            $freshCompany->update([
                'is_initialized' => true,
            ]);
        });
    }

    private function makeLeaveShortCode(string $name): string
    {
        $parts = preg_split('/\s+/', trim($name)) ?: [];
        $code = collect($parts)
            ->filter()
            ->map(static fn (string $part): string => Str::upper(Str::substr($part, 0, 1)))
            ->implode('');

        return Str::limit($code ?: Str::upper(Str::substr($name, 0, 3)), 10, '');
    }
}
