<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Models\AttendanceLog;
use App\Models\AttendanceSetting;
use App\Models\EmployeeBonus;
use App\Models\EmployeeCommission;
use App\Models\EmployeePenalty;
use App\Models\EmployeeWithdrawal;
use App\Models\MonthlySettlement;
use App\Models\User;
use App\Support\TwoFactor;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;

class ProfileController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function index()
    {
        $user = Auth::user();

        $employeeAccounts = null;
        $employeeAccountsPeriodFrom = null;
        $employeeAccountsPeriodTo = null;

        $employee = $user?->employee;
        if ($employee) {
            $tz = 'Asia/Baghdad';
            $nowLocal = Carbon::now($tz);
            $lastSettlement = MonthlySettlement::query()
                ->orderByDesc('settled_at')
                ->orderByDesc('date_to')
                ->orderByDesc('id')
                ->first();

            $periodFromLocal = $lastSettlement?->settled_at
                ? $lastSettlement->settled_at->copy()->setTimezone($tz)->addSecond()
                : ($lastSettlement?->date_to
                    ? $lastSettlement->date_to->copy()->addDay()->startOfDay()
                    : $nowLocal->copy()->startOfMonth());

            $periodToLocal = $nowLocal->copy()->endOfDay();
            $fromUtc = $periodFromLocal->copy()->setTimezone('UTC');
            $toUtc = $periodToLocal->copy()->setTimezone('UTC');

            $baseSalary = (int) ($employee->base_salary ?? 0);

            $commissionsTotal = (int) EmployeeCommission::query()
                ->where('employee_id', $employee->id)
                ->where('status', 'pending')
                ->whereBetween('eligible_at', [$fromUtc, $toUtc])
                ->sum('commission_amount');

            $bonusesTotal = (int) EmployeeBonus::query()
                ->where('employee_id', $employee->id)
                ->whereBetween('created_at', [$fromUtc, $toUtc])
                ->sum('amount');

            $penaltiesTotal = (int) EmployeePenalty::query()
                ->where('employee_id', $employee->id)
                ->whereBetween('created_at', [$fromUtc, $toUtc])
                ->sum('amount');

            $withdrawalsTotal = (int) EmployeeWithdrawal::query()
                ->where('employee_id', $employee->id)
                ->whereBetween('created_at', [$fromUtc, $toUtc])
                ->sum('amount');

            $absentDaysTotal = (int) AttendanceLog::query()
                ->where('employee_id', $employee->id)
                ->where('type', 'check_in')
                ->where('attendance_status', 'absent')
                ->whereBetween('logged_at', [$fromUtc, $toUtc])
                ->count();

            $settings = AttendanceSetting::query()->first();
            $absenceDeductionDays = (int) ($settings?->absence_deduction_days ?? 1);
            $absenceDeductionDays = max(0, min(30, $absenceDeductionDays));

            $dailyRate = $baseSalary > 0 ? ($baseSalary / 30) : 0;
            $absencesTotal = (int) round($absentDaysTotal * $absenceDeductionDays * $dailyRate);

            $netTotal = $baseSalary
                + $commissionsTotal
                + $bonusesTotal
                - $penaltiesTotal
                - $withdrawalsTotal
                - $absencesTotal;

            $employeeAccounts = [
                'base_salary' => $baseSalary,
                'commissions_total' => $commissionsTotal,
                'bonuses_total' => $bonusesTotal,
                'penalties_total' => $penaltiesTotal,
                'withdrawals_total' => $withdrawalsTotal,
                'absences_total' => $absencesTotal,
                'net_total' => $netTotal,
            ];

            $employeeAccountsPeriodFrom = $periodFromLocal;
            $employeeAccountsPeriodTo = $periodToLocal;
        }

        return view('profile.index', [
            'employee_accounts' => $employeeAccounts,
            'employee_accounts_period_from' => $employeeAccountsPeriodFrom,
            'employee_accounts_period_to' => $employeeAccountsPeriodTo,
        ]);
    }

    public function updateProfile(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $data = $request->validate([
            'name' => ['required', 'string', 'max:255'],
        ]);

        $user->forceFill([
            'name' => $data['name'],
        ])->save();

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

    public function updateAvatar(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $employee = $user->employee;
        if (! $employee) {
            abort(403);
        }

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

        $oldAvatarPath = $employee->avatar_path;
        $avatarPath = $request->file('avatar')->store('employees/avatars', 'public');

        $employee->forceFill([
            'avatar_path' => $avatarPath,
        ])->save();

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

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

    public function updatePassword(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $data = $request->validate([
            'current_password' => ['required', 'string'],
            'password' => ['required', 'string', 'min:8', 'confirmed'],
        ]);

        if (! Hash::check($data['current_password'], (string) $user->password)) {
            return back()->withErrors([
                'current_password' => __('auth.password'),
            ]);
        }

        $user->forceFill([
            'password' => $data['password'],
        ])->save();

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

    public function startTwoFactor(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $secret = TwoFactor::generateBase32Secret();

        $user->forceFill([
            'two_factor_enabled' => false,
            'two_factor_secret' => null,
            'two_factor_pending_secret' => Crypt::encryptString($secret),
        ])->save();

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

    public function confirmTwoFactor(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $data = $request->validate([
            'code' => ['required', 'string', 'max:10'],
        ]);

        $pending = (string) ($user->two_factor_pending_secret ?? '');
        $secret = $pending !== '' ? Crypt::decryptString($pending) : '';
        if ($secret === '') {
            return back()->withErrors([
                'code' => __('system_assistant.error_generic'),
            ]);
        }

        $code = preg_replace('/\s+/', '', $data['code']) ?? '';
        if (! TwoFactor::verifyTotpCode($secret, $code)) {
            return back()
                ->withErrors(['code' => __('common.invalid')]);
        }

        $user->forceFill([
            'two_factor_enabled' => true,
            'two_factor_secret' => Crypt::encryptString($secret),
            'two_factor_pending_secret' => null,
        ])->save();

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

    public function disableTwoFactor(Request $request)
    {
        $user = Auth::user();
        if (! $user instanceof User) {
            abort(403);
        }

        $data = $request->validate([
            'current_password' => ['required', 'string'],
        ]);

        if (! Hash::check($data['current_password'], (string) $user->password)) {
            return back()->withErrors([
                'current_password' => __('auth.password'),
            ]);
        }

        $user->forceFill([
            'two_factor_enabled' => false,
            'two_factor_secret' => null,
            'two_factor_pending_secret' => null,
        ])->save();

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