<?php

namespace App\Http\Controllers;

use App\Models\Employee;
use App\Models\EmployeeServiceCommission;
use App\Models\Role;
use App\Models\User;
use App\Services\EmployeeCommissionService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;

class EmployeesController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:employees.view')->only(['index']);
        $this->middleware('permission:employees.create')->only(['store']);
        $this->middleware('permission:employees.update')->only(['update', 'toggleActive']);
        $this->middleware('permission:employees.delete')->only(['destroy']);
    }

    public function index(EmployeeCommissionService $commissionService)
    {
        $employees = Employee::query()
            ->with(['role', 'user', 'serviceCommissions'])
            ->latest()
            ->paginate(20);

        $roles = Role::query()
            ->orderBy('name')
            ->get();

        $users = User::query()
            ->orderBy('name')
            ->get();

        $serviceCommissionDefs = collect($commissionService::serviceDefinitions())
            ->map(function (array $def) use ($commissionService) {
                $def['form_key'] = $commissionService::formKeyFromServiceKey($def['service_key']);

                return $def;
            })
            ->values();

        return view('pages.employees', compact('employees', 'roles', 'users', 'serviceCommissionDefs'));
    }

    public function store(Request $request, EmployeeCommissionService $commissionService)
    {
        $serviceCommissionDefs = collect($commissionService::serviceDefinitions())
            ->map(function (array $def) use ($commissionService) {
                $def['form_key'] = $commissionService::formKeyFromServiceKey($def['service_key']);

                return $def;
            })
            ->values();

        $rules = [
            'full_name' => ['required', 'string', 'max:255'],
            'address' => ['nullable', 'string', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'avatar' => ['nullable', 'image', 'max:10240'],
            'job_title' => ['nullable', 'string', 'max:255'],
            'attendance_time' => ['required', 'regex:/^\\d{2}:\\d{2}(:\\d{2})?$/'],
            'departure_time' => ['required', 'regex:/^\\d{2}:\\d{2}(:\\d{2})?$/'],
            'allow_outside_company' => ['nullable', 'boolean'],
            'notes' => ['nullable', 'string'],
            'base_salary' => ['required', 'integer', 'min:0'],
            'role_id' => ['required', 'integer', 'exists:roles,id'],
            'general_percentage' => ['required', 'integer', 'min:0', 'max:100'],
            'role_percentage' => ['required', 'integer', 'min:0', 'max:100'],
            'username' => ['required', 'string', 'max:255', 'unique:users,username'],
            'password' => ['required', 'string', 'min:6', 'confirmed'],
            'password_confirmation' => ['required', 'string', 'min:6'],
        ];

        foreach ($serviceCommissionDefs as $def) {
            $rules['commissions.'.$def['form_key'].'.sales_percentage'] = ['required', 'integer', 'min:0', 'max:100'];
            if ($def['supports_work']) {
                $rules['commissions.'.$def['form_key'].'.work_percentage'] = ['required', 'integer', 'min:0', 'max:100'];
            }
        }

        $validator = Validator::make($request->all(), $rules, [
            'avatar.image' => 'الملف المرفق يجب أن يكون صورة.',
            'avatar.max' => 'حجم الصورة يجب ألا يتجاوز 10 ميغابايت.',
        ]);

        if ($validator->fails()) {
            return redirect()
                ->route('employees')
                ->withErrors($validator)
                ->withInput()
                ->with('open_employee_add_modal', true);
        }

        $data = $validator->validated();
        $avatarPath = null;
        if ($request->hasFile('avatar')) {
            $avatarPath = $request->file('avatar')->store('employees/avatars', 'public');
        }
        $data['attendance_time'] = $this->normalizeTimeInput($data['attendance_time']);
        $data['departure_time'] = $this->normalizeTimeInput($data['departure_time']);
        $data['allow_outside_company'] = (bool) ($data['allow_outside_company'] ?? false);
        $data['is_active'] = true;
        $data['activated_at'] = now();
        $data['deactivated_at'] = null;
        $commissions = $data['commissions'] ?? [];
        unset($data['commissions']);
        unset($data['avatar']);
        if ($avatarPath) {
            $data['avatar_path'] = $avatarPath;
        }

        $employee = DB::transaction(function () use ($data, $commissions, $serviceCommissionDefs) {
            $username = $data['username'];
            $password = $data['password'];

            unset($data['username'], $data['password'], $data['password_confirmation']);

            $user = User::query()->create([
                'name' => $data['full_name'],
                'username' => $username,
                'email' => (string) Str::uuid().'@cpp.local',
                'password' => Hash::make($password),
            ]);

            $roleId = (int) ($data['role_id'] ?? 0);
            if ($roleId > 0) {
                $user->roles()->sync([$roleId]);
            }

            $data['user_id'] = $user->id;

            $employee = Employee::query()->create($data);
            $this->syncEmployeeServiceCommissions($employee, $commissions, $serviceCommissionDefs);

            return $employee;
        });

        return redirect()->route('employees')->with('success', __('employees.messages.created'));
    }

    public function update(Request $request, Employee $employee, EmployeeCommissionService $commissionService)
    {
        $serviceCommissionDefs = collect($commissionService::serviceDefinitions())
            ->map(function (array $def) use ($commissionService) {
                $def['form_key'] = $commissionService::formKeyFromServiceKey($def['service_key']);

                return $def;
            })
            ->values();

        $rules = [
            'full_name' => ['required', 'string', 'max:255'],
            'address' => ['nullable', 'string', 'max:255'],
            'phone' => ['nullable', 'string', 'max:50'],
            'avatar' => ['nullable', 'image', 'max:10240'],
            'job_title' => ['nullable', 'string', 'max:255'],
            'attendance_time' => ['required', 'regex:/^\\d{2}:\\d{2}(:\\d{2})?$/'],
            'departure_time' => ['required', 'regex:/^\\d{2}:\\d{2}(:\\d{2})?$/'],
            'allow_outside_company' => ['nullable', 'boolean'],
            'notes' => ['nullable', 'string'],
            'base_salary' => ['required', 'integer', 'min:0'],
            'role_id' => ['required', 'integer', 'exists:roles,id'],
            'general_percentage' => ['required', 'integer', 'min:0', 'max:100'],
            'role_percentage' => ['required', 'integer', 'min:0', 'max:100'],
            'username' => [
                'required',
                'string',
                'max:255',
                Rule::unique('users', 'username')->ignore($employee->user_id),
            ],
            'password' => ['nullable', 'string', 'min:6', 'confirmed'],
            'password_confirmation' => ['nullable', 'string', 'min:6'],
        ];

        foreach ($serviceCommissionDefs as $def) {
            $rules['commissions.'.$def['form_key'].'.sales_percentage'] = ['required', 'integer', 'min:0', 'max:100'];
            if ($def['supports_work']) {
                $rules['commissions.'.$def['form_key'].'.work_percentage'] = ['required', 'integer', 'min:0', 'max:100'];
            }
        }

        $validator = Validator::make($request->all(), $rules, [
            'avatar.image' => 'الملف المرفق يجب أن يكون صورة.',
            'avatar.max' => 'حجم الصورة يجب ألا يتجاوز 10 ميغابايت.',
        ]);

        if ($validator->fails()) {
            return redirect()
                ->route('employees')
                ->withErrors($validator)
                ->withInput()
                ->with('edit_employee_id', $employee->id);
        }

        $data = $validator->validated();
        $avatarPath = null;
        $oldAvatarPath = $employee->avatar_path;
        if ($request->hasFile('avatar')) {
            $avatarPath = $request->file('avatar')->store('employees/avatars', 'public');
        }
        $data['attendance_time'] = $this->normalizeTimeInput($data['attendance_time']);
        $data['departure_time'] = $this->normalizeTimeInput($data['departure_time']);
        $data['allow_outside_company'] = (bool) ($data['allow_outside_company'] ?? false);
        $commissions = $data['commissions'] ?? [];
        unset($data['commissions']);
        unset($data['avatar']);
        if ($avatarPath) {
            $data['avatar_path'] = $avatarPath;
        }

        DB::transaction(function () use ($employee, $data, $commissions, $serviceCommissionDefs) {
            $username = $data['username'];
            $password = $data['password'] ?? null;

            unset($data['username'], $data['password'], $data['password_confirmation']);

            $employee->update($data);
            $this->syncEmployeeServiceCommissions($employee, $commissions, $serviceCommissionDefs);

            $user = $employee->user;
            if (! $user) {
                $user = User::query()->create([
                    'name' => $employee->full_name,
                    'username' => $username,
                    'email' => (string) Str::uuid().'@cpp.local',
                    'password' => Hash::make((string) ($password ?? Str::random(24))),
                ]);

                $employee->update(['user_id' => $user->id]);
            }

            $user->name = $employee->full_name;
            $user->username = $username;
            if ($password !== null && $password !== '') {
                $user->password = Hash::make($password);
            }
            $user->save();

            $roleId = (int) ($employee->role_id ?? 0);
            if ($roleId > 0) {
                $user->roles()->sync([$roleId]);
            }
        });

        if ($avatarPath && $oldAvatarPath && $oldAvatarPath !== $avatarPath) {
            Storage::disk('public')->delete($oldAvatarPath);
        }

        return redirect()->route('employees')->with('success', __('employees.messages.updated'));
    }

    public function destroy(Employee $employee)
    {
        $employee->delete();

        return redirect()->route('employees')->with('success', __('employees.messages.deleted'));
    }

    public function toggleActive(Request $request, Employee $employee)
    {
        DB::transaction(function () use ($employee) {
            if ((bool) ($employee->is_active ?? true)) {
                $employee->forceFill([
                    'is_active' => false,
                    'deactivated_at' => now(),
                ])->save();
            } else {
                $employee->forceFill([
                    'is_active' => true,
                    'activated_at' => now(),
                    'deactivated_at' => null,
                ])->save();
            }
        });

        return back()->with('success', __('common.saved_successfully'));
    }

    private function syncEmployeeServiceCommissions(Employee $employee, array $commissions, $serviceCommissionDefs): void
    {
        foreach ($serviceCommissionDefs as $def) {
            $formKey = $def['form_key'];
            $serviceKey = $def['service_key'];
            $salesPercentage = (int) ($commissions[$formKey]['sales_percentage'] ?? 0);

            $supportsWork = (bool) ($def['supports_work'] ?? false);
            $workPercentage = null;
            if ($supportsWork) {
                $workPercentage = (int) ($commissions[$formKey]['work_percentage'] ?? 0);
            }

            EmployeeServiceCommission::query()->updateOrCreate(
                [
                    'employee_id' => $employee->id,
                    'service_key' => $serviceKey,
                ],
                [
                    'sales_percentage' => $salesPercentage,
                    'work_percentage' => $supportsWork ? $workPercentage : null,
                    'work_trigger_type' => (string) ($def['work_trigger_type'] ?? 'none'),
                ]
            );
        }
    }

    private function normalizeTimeInput(?string $time): string
    {
        $time = $time !== null ? trim($time) : '';
        if (preg_match('/^\\d{2}:\\d{2}$/', $time)) {
            return $time.':00';
        }

        return $time;
    }
}
