<?php

namespace App\Http\Controllers;

use App\Models\StageAcademyActivation;
use App\Models\StageAcademyUser;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Facades\Validator;
use Illuminate\Validation\Rule;

class StageAcademyController extends Controller
{
    public function __construct()
    {
        $this->middleware('permission:stage_academy.view')->only(['index']);
        $this->middleware('permission:stage_academy.courses.view')->only(['courses']);

        $this->middleware('permission:stage_academy.users.view|pos.stage_academy.users.view')->only(['users', 'userCourses']);
        $this->middleware('permission:stage_academy.users.create|pos.stage_academy.users.create')->only(['storeUser']);
        $this->middleware('permission:stage_academy.users.update|pos.stage_academy.users.update')->only(['updateUser', 'resetUserPassword']);
        $this->middleware('permission:stage_academy.users.delete|pos.stage_academy.users.delete')->only(['destroyUser']);
    }

    private function usersIndexRouteName(Request $request): string
    {
        if ($request->routeIs('pos.stage-academy.*')) {
            return 'pos.stage-academy.users';
        }

        return 'stage-academy.users';
    }

    public function index()
    {
        return view('stage_academy.index');
    }

    public function courses()
    {
        return view('stage_academy.courses');
    }

    public function users(Request $request)
    {
        if ($request->routeIs('stage-academy.users')) {
            return redirect()->route('pos.stage-academy.users', $request->query());
        }

        $countries = $this->countries();
        $provincesByCountry = $this->provincesByCountry();
        $provinceLabels = $this->provinceLabels();

        $search = trim((string) $request->query('search', ''));
        $parts = $this->smartSearchParts($search);
        $search = $parts['search'];
        $searchRaw = $parts['searchRaw'];
        $searchDigits = $parts['searchDigits'];
        $terms = $parts['terms'];
        $date = (string) $request->query('date', '');

        $users = StageAcademyUser::query()
            ->when($search !== '', function ($query) use ($searchRaw, $searchDigits, $terms) {
                $query->where(function ($q) use ($searchRaw, $searchDigits, $terms) {
                    $q->where(function ($nameQ) use ($terms) {
                        foreach ($terms as $t) {
                            $nameQ->where('name', 'like', '%'.$t.'%');
                        }
                    })->orWhere('phone', 'like', '%'.$searchRaw.'%');

                    if ($searchDigits !== '') {
                        $q->orWhere('phone', 'like', '%'.$searchDigits.'%');
                    }
                });
            })
            ->when($date !== '', function ($query) use ($date) {
                $query->whereDate('created_at', $date);
            })
            ->latest()
            ->paginate(20)
            ->appends($request->all());

        return view('stage_academy.users', compact('users', 'countries', 'provincesByCountry', 'provinceLabels', 'search', 'date'));
    }

    public function storeUser(Request $request)
    {
        $isPosStageAcademy = $request->routeIs('pos.stage-academy.*');
        $countries = array_keys($this->countries());
        $provincesByCountry = $this->provincesByCountry();

        $rules = [
            'name' => ['required', 'string', 'max:255'],
            'country' => ['required', Rule::in($countries)],
            'province' => ['nullable', 'string', 'max:255', Rule::requiredIf(fn () => $request->input('country') === 'iq')],
            'gender' => ['required', Rule::in(['male', 'female'])],
            'phone' => ['required', 'string', 'max:50', 'unique:stage_academy_users,phone'],
        ];

        if (! $isPosStageAcademy) {
            $rules['password'] = ['required', 'string'];
            $rules['password_confirmation'] = ['required', 'same:password'];
        }

        $validator = Validator::make($request->all(), $rules);

        $validator->after(function ($validator) use ($request, $provincesByCountry) {
            $country = $request->input('country');
            $province = $request->input('province');
            $allowedProvinces = $provincesByCountry[$country] ?? [];

            if ($country !== 'iq') {
                return;
            }

            if (! in_array($province, $allowedProvinces, true)) {
                $validator->errors()->add('province', __('stage_academy.users.validation.invalid_province'));
            }
        });

        if ($validator->fails()) {
            return redirect()
                ->route($this->usersIndexRouteName($request))
                ->withErrors($validator)
                ->withInput()
                ->with('open_add_modal', true);
        }

        $data = $validator->validated();
        $provinceToSave = $data['country'] === 'iq' ? ($data['province'] ?? '') : '';
        $plainPassword = $isPosStageAcademy ? '123456789' : $data['password'];

        StageAcademyUser::query()->create([
            'name' => $data['name'],
            'country' => $data['country'],
            'province' => $provinceToSave,
            'gender' => $data['gender'],
            'phone' => $data['phone'],
            'password' => Hash::make($plainPassword),
            'source_type' => $isPosStageAcademy ? 'pos' : 'admin',
        ]);

        return redirect()->route($this->usersIndexRouteName($request))->with('success', __('common.saved_successfully'));
    }

    public function updateUser(Request $request, StageAcademyUser $user)
    {
        $countries = array_keys($this->countries());
        $provincesByCountry = $this->provincesByCountry();

        $validator = Validator::make($request->all(), [
            'name' => ['required', 'string', 'max:255'],
            'country' => ['required', Rule::in($countries)],
            'province' => ['nullable', 'string', 'max:255', Rule::requiredIf(fn () => $request->input('country') === 'iq')],
            'gender' => ['required', Rule::in(['male', 'female'])],
            'phone' => [
                'required',
                'string',
                'max:50',
                Rule::unique('stage_academy_users', 'phone')->ignore($user->id),
            ],
        ]);

        $validator->after(function ($validator) use ($request, $provincesByCountry) {
            $country = $request->input('country');
            $province = $request->input('province');
            $allowedProvinces = $provincesByCountry[$country] ?? [];

            if ($country !== 'iq') {
                return;
            }

            if (! in_array($province, $allowedProvinces, true)) {
                $validator->errors()->add('province', __('stage_academy.users.validation.invalid_province'));
            }
        });

        if ($validator->fails()) {
            return redirect()
                ->route($this->usersIndexRouteName($request))
                ->withErrors($validator)
                ->withInput()
                ->with('edit_user_id', $user->id);
        }

        $data = $validator->validated();
        $provinceToSave = $data['country'] === 'iq' ? ($data['province'] ?? '') : '';

        $user->update([
            'name' => $data['name'],
            'country' => $data['country'],
            'province' => $provinceToSave,
            'gender' => $data['gender'],
            'phone' => $data['phone'],
        ]);

        return redirect()->route($this->usersIndexRouteName($request))->with('success', __('common.saved_successfully'));
    }

    public function destroyUser(Request $request, StageAcademyUser $user)
    {
        $user->delete();

        return redirect()->route($this->usersIndexRouteName($request))->with('success', __('common.deleted_successfully'));
    }

    public function resetUserPassword(Request $request, StageAcademyUser $user)
    {
        $user->update([
            'password' => Hash::make('123456789'),
            'password_reset_at' => now(),
        ]);

        return redirect()->route($this->usersIndexRouteName($request))->with('success', __('stage_academy.users.password_reset_done'));
    }

    public function userCourses(StageAcademyUser $user)
    {
        if (! Schema::hasTable('stage_academy_activations')) {
            $activations = collect();
            $courseProgress = [];

            return view('stage_academy.users_courses', compact('user', 'activations', 'courseProgress'));
        }

        $activations = StageAcademyActivation::query()
            ->with(['course.trainer', 'course.institution', 'creator'])
            ->where('user_id', $user->id)
            ->latest()
            ->get();

        $courseIds = $activations->pluck('course_id')->filter()->unique()->values()->all();
        $courseProgress = $this->courseProgressPercentages($user->id, $courseIds);

        return view('stage_academy.users_courses', compact('user', 'activations', 'courseProgress'));
    }

    private function courseProgressPercentages(int $userId, array $courseIds): array
    {
        if ($courseIds === []) {
            return [];
        }

        if (! Schema::hasTable('stage_academy_course_video_progress')) {
            return [];
        }

        $courseIds = array_values(array_unique(array_map('intval', $courseIds)));

        $videosQuery = DB::table('stage_academy_course_videos')
            ->whereIn('stage_academy_course_videos.course_id', $courseIds);

        if (Schema::hasColumn('stage_academy_course_videos', 'deleted_at')) {
            $videosQuery->whereNull('stage_academy_course_videos.deleted_at');
        }

        $videoCountByCourse = (clone $videosQuery)
            ->selectRaw('stage_academy_course_videos.course_id, COUNT(*) as video_count')
            ->groupBy('stage_academy_course_videos.course_id')
            ->pluck('video_count', 'stage_academy_course_videos.course_id')
            ->all();

        $durationsSub = DB::table('stage_academy_course_video_progress')
            ->selectRaw('video_id, MAX(video_duration_seconds) as max_duration_seconds')
            ->groupBy('video_id');

        $durationExpr = Schema::hasColumn('stage_academy_course_videos', 'duration_seconds')
            ? 'COALESCE(stage_academy_course_videos.duration_seconds, up.video_duration_seconds, p.max_duration_seconds, 0)'
            : 'COALESCE(up.video_duration_seconds, p.max_duration_seconds, 0)';

        $fractionExpr = 'CASE'
            .' WHEN '.$durationExpr.' > 0'
            .' THEN (LEAST(COALESCE(up.watched_seconds, 0), '.$durationExpr.') / '.$durationExpr.')'
            .' ELSE 0'
            .' END';

        $fractionSumByCourse = (clone $videosQuery)
            ->leftJoin('stage_academy_course_video_progress as up', function ($join) use ($userId) {
                $join->on('up.video_id', '=', 'stage_academy_course_videos.id')
                    ->where('up.user_id', '=', $userId);
            })
            ->leftJoinSub($durationsSub, 'p', function ($join) {
                $join->on('p.video_id', '=', 'stage_academy_course_videos.id');
            })
            ->selectRaw('stage_academy_course_videos.course_id, COALESCE(SUM('.$fractionExpr.'), 0) as fraction_sum')
            ->groupBy('stage_academy_course_videos.course_id')
            ->pluck('fraction_sum', 'stage_academy_course_videos.course_id')
            ->all();

        $result = [];
        foreach ($courseIds as $courseId) {
            $videoCount = (int) ($videoCountByCourse[$courseId] ?? 0);
            $fractionSum = (float) ($fractionSumByCourse[$courseId] ?? 0);

            if ($videoCount <= 0) {
                $result[$courseId] = 0;

                continue;
            }

            $result[$courseId] = (int) min(100, max(0, round(($fractionSum / $videoCount) * 100)));
        }

        return $result;
    }

    public function activations(Request $request)
    {
        return redirect()->route('pos.stage-academy.activations', $request->query());
    }

    public function banner()
    {
        return view('stage_academy.banner');
    }

    public function offers()
    {
        return view('stage_academy.offers');
    }

    private function countries(): array
    {
        $regions = require base_path('vendor/nesbot/carbon/src/Carbon/List/regions.php');
        $countries = [];

        foreach ($regions as $code => $name) {
            $countries[strtolower($code)] = $name;
        }

        $iraqName = $countries['iq'] ?? 'Iraq';
        unset($countries['iq']);
        asort($countries, SORT_NATURAL | SORT_FLAG_CASE);

        return ['iq' => $iraqName] + $countries;
    }

    private function provincesByCountry(): array
    {
        return [
            'iq' => [
                'baghdad',
                'basra',
                'nineveh',
                'erbil',
                'najaf',
                'karbala',
                'wasit',
                'babel',
                'dhi_qar',
                'maysan',
                'anbar',
                'diyala',
                'kirkuk',
                'salahaddin',
                'sulaymaniyah',
                'duhok',
                'qadisiyah',
                'muthanna',
                'halabja',
            ],
        ];
    }

    private function provinceLabels(): array
    {
        return [
            'baghdad' => 'Baghdad',
            'basra' => 'Basra',
            'nineveh' => 'Nineveh',
            'erbil' => 'Erbil',
            'najaf' => 'Najaf',
            'karbala' => 'Karbala',
            'wasit' => 'Wasit',
            'babel' => 'Babil',
            'dhi_qar' => 'Dhi Qar',
            'maysan' => 'Maysan',
            'anbar' => 'Al Anbar',
            'diyala' => 'Diyala',
            'kirkuk' => 'Kirkuk',
            'salahaddin' => 'Salah al-Din',
            'sulaymaniyah' => 'Sulaymaniyah',
            'duhok' => 'Duhok',
            'qadisiyah' => 'Al-Qadisiyah',
            'muthanna' => 'Al Muthanna',
            'halabja' => 'Halabja',
        ];
    }
}
