<?php

namespace App\Http\Controllers;

use App\Models\Plan;
use App\Models\PlanUser;
use App\Models\Role;
use App\Models\User;
use App\Notifications\InviteUserNotification;
use App\Services\PermissionAccessService;
use App\Services\PlanService;
use App\Services\UserLogger;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Route;
use App\Models\PaymentLedger;
use Carbon\Carbon;
use Illuminate\Support\Str;
use Yajra\DataTables\Facades\DataTables;

class UserController extends Controller
{
    /**
     * Show user list page. DataTables JSON endpoint for user table.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Contracts\View\View | \Illuminate\Http\JsonResponse
     */
    public function index(Request $request)
    {
        if (!hasPermission('user.manage', PermissionAccessService::VIEW)) {
            abort(404, 'Unauthorized.');
        }

        if ($request->ajax()) {
            $query = User::with('roles');

            $status = $request->input('status');
            if ($status !== null && is_numeric($status)) {
                $query->where('status', (int) $status);
            } else {
                $query->withTrashed(); // <- Only when viewing All statuses
            }

            $editPermission = hasPermission('user.manage', PermissionAccessService::UPDATE)? '' : 'disabled';
            $deletePermission = hasPermission('user.manage', PermissionAccessService::DELETE)? '' : 'disabled';

            return DataTables::of($query)
                ->filter(function ($query) use ($request) {
                    if ($request->has('search') && $request->input('search.value') !== null) {
                        $search = $request->input('search.value');
                        $query->where(function ($q) use ($search) {
                            $q->where('name', 'like', "%{$search}%")
                            ->orWhere('ic_no', 'like', "%{$search}%")
                            ->orWhere('email', 'like', "%{$search}%");
                        });
                    }
                })
                ->editColumn('created_at', function ($user) {
                    return $user->created_at_formatted;
                })
                ->addColumn('status_label', function ($user) {
                    return $this->getStatusBadge($user->status);
                })
                ->addColumn('status_aku_janji', function ($user) {
                    return $this->getStatusAkuJanjiBadge($user->tnc_upload_at ?? null);
                })
                ->addColumn('activate_account', function ($user) use ($editPermission){
                    return view('partials.switch', compact('user', 'editPermission'))->render();
                })
                ->addColumn('action', function ($user) use ($editPermission, $deletePermission){
                    $viewUrl = route('user.view', $user->id);
                    $editUrl = route('user.edit', $user->id);
                    $deleteUrl = route('user.destroy', $user->id);
                    $isDeleted = $user->trashed();
                    return view('partials.actions-buttons', compact('viewUrl', 'editUrl', 'deleteUrl', 'editPermission', 'deletePermission', 'isDeleted'))->render();
                })
                ->rawColumns(['status_label', 'action', 'status_aku_janji', 'activate_account'])
                ->make(true);
        }

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName());
        return view('user.index');
    }

    /**
     * Show user creation form.
     *
     * @return \Illuminate\Contracts\View\View
     */
    public function create()
    {
        if (!hasPermission('user.manage', PermissionAccessService::CREATE)) {
            abort(404, 'Unauthorized.');
        }

        $statuses = User::getStatusOptions();
        $roles = Role::getActiveRole();
        $kps = \App\Models\KP::orderBy('name')->get(); // Fetch KPs for Bank Section

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName());
        return view('user.create', compact('statuses', 'roles', 'kps'));
    }

    /**
     * Store a new user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store(Request $request)
    {
        if (!hasPermission('user.manage', PermissionAccessService::CREATE)) {
            abort(404, 'Unauthorized.');
        }

        $validated = $request->validate([
            'name'              => 'required|string|max:100',
            'phone_no'          => 'nullable|string|max:100',
            'address'           => 'nullable|string|max:500',
            'email'             => 'nullable|email|max:255',
            'ic_no'             => 'required|string',
            'password'          => 'required|string|min:4',
            'status'            => 'required|in:0,1',

            'bank_account_no'   => 'required|string|max:50',
            'bank_name'         => 'nullable|string|max:100',
            'name_on_bank'      => 'nullable|string|max:255',

            // KP Bank Validations
            'kp_bank'              => 'nullable|array',
            'kp_bank.*.bank_name'  => 'nullable|string|max:100',
            'kp_bank.*.account_no' => 'nullable|string|max:50',

            'nok_name'           => 'nullable|string|max:255',
            'nok_ic_no'          => 'nullable|string|max:255',
            'nok_email'          => 'nullable|string|max:255',
            'nok_phone_no'       => 'nullable|string|max:50',
            'nok_relationship'   => 'nullable|string|max:100',
            'nok_name_on_bank'   => 'nullable|string|max:255',
            'nok_bank_account_no'=> 'nullable|string|max:50',
            'nok_bank_name'      => 'nullable|string|max:100',

            'roles'     => ['nullable', 'array'],
            'roles.*'   => ['exists:roles,id'],
        ]);

        $user = User::create([
            'name'     => $validated['name'],
            'phone_no' => $validated['phone_no'],
            'address'  => $validated['address'],
            'email'    => $validated['email'],
            'ic_no'    => $validated['ic_no'],

            'bank_account_no' => $validated['bank_account_no'],
            'bank_name'       => $validated['bank_name'],
            'name_on_bank'    => $validated['name_on_bank'],

            'nok_name'              => $validated['nok_name'],
            'nok_ic_no'             => $validated['nok_ic_no'],
            'nok_email'             => $validated['nok_email'],
            'nok_phone_no'          => $validated['nok_phone_no'],
            'nok_relationship'      => $validated['nok_relationship'],
            'nok_name_on_bank'      => $validated['nok_name_on_bank'],
            'nok_bank_account_no'   => $validated['nok_bank_account_no'],
            'nok_bank_name'         => $validated['nok_bank_name'],

            'password'   => $validated['password'],
        ]);

        // Save KP Bank Accounts
        if ($request->filled('kp_bank')) {
            foreach ($request->kp_bank as $kpId => $bankData) {
                if (!empty($bankData['bank_name']) || !empty($bankData['account_no'])) {
                    $user->bankAccounts()->create([
                        'kp_id'      => $kpId,
                        'name'       => $bankData['bank_name'],
                        'account_no' => $bankData['account_no']
                    ]);
                }
            }
        }

        $user->roles()->sync($request->input('roles', [4]));

        UserLogger::log(UserLogger::ACTION_CREATE, Route::currentRouteName(), $user->id);
        return redirect()->route('user.index')->with('success', 'User created successfully.');
    }

    /**
     * Show user edit form.
     *
     * @param  int  $id
     * @return \Illuminate\Contracts\View\View
     */
    public function edit(int $id)
    {
        if (!hasPermission('user.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $user = User::withTrashed()->findOrFail($id);

        $statuses = User::getStatusOptions();
        $roles = Role::getActiveRole();
        $assignedRoles = $user->roles->pluck('id')->toArray();
        $kps = \App\Models\KP::orderBy('name')->get(); // Fetch KPs for Bank Section

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName(), $id);
        return view('user.edit', compact('user', 'statuses', 'roles', 'assignedRoles', 'kps'));
    }

    /**
     * Update existing user.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function update(Request $request, int $id)
    {
        if (!hasPermission('user.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $user = User::withTrashed()->findOrFail($id);

        $validated = $request->validate([
            'name'              => 'required|string|max:100',
            'phone_no'          => 'nullable|string|max:100',
            'address'           => 'nullable|string|max:500',
            'email'             => 'nullable|email|max:255',
            'status'            => 'required|in:0,1',
            'password'          => 'nullable|string',

            'bank_account_no'   => 'nullable|string|max:50',
            'bank_name'         => 'nullable|string|max:100',
            'name_on_bank'      => 'nullable|string|max:255',

            // KP Bank Validations
            'kp_bank'              => 'nullable|array',
            'kp_bank.*.bank_name'  => 'nullable|string|max:100',
            'kp_bank.*.account_no' => 'nullable|string|max:50',

            'nok_name'           => 'nullable|string|max:255',
            'nok_ic_no'          => 'nullable|string|max:255',
            'nok_email'          => 'nullable|string|max:255',
            'nok_phone_no'       => 'nullable|string|max:50',
            'nok_relationship'   => 'nullable|string|max:100',
            'nok_name_on_bank'   => 'nullable|string|max:255',
            'nok_bank_account_no'=> 'nullable|string|max:50',
            'nok_bank_name'      => 'nullable|string|max:100',

            'roles'         => ['nullable', 'array'],
            'roles.*'       => ['exists:roles,id'],
        ]);

        $user->update([
            'name'     => $validated['name'],
            'phone_no' => $validated['phone_no'],
            'address'  => $validated['address'],
            'email'    => $validated['email'],

            'bank_account_no' => $validated['bank_account_no'],
            'bank_name'       => $validated['bank_name'],
            'name_on_bank'    => $validated['name_on_bank'],

            'nok_name'              => $validated['nok_name'],
            'nok_ic_no'             => $validated['nok_ic_no'],
            'nok_email'             => $validated['nok_email'],
            'nok_phone_no'          => $validated['nok_phone_no'],
            'nok_relationship'      => $validated['nok_relationship'],
            'nok_name_on_bank'      => $validated['nok_name_on_bank'],
            'nok_bank_account_no'   => $validated['nok_bank_account_no'],
            'nok_bank_name'         => $validated['nok_bank_name'],
        ]);

        if (!empty($validated['password'])) {
            $user->update(['password' => $validated['password']]);
        }

        // Update KP Banks directly
        if ($request->has('kp_bank')) {
            foreach ($request->kp_bank as $kpId => $bankData) {
                $bankAccount = $user->bankAccounts()->where('kp_id', $kpId)->first();

                // If the admin typed something in
                if (!empty($bankData['bank_name']) || !empty($bankData['account_no'])) {
                    if ($bankAccount) {
                        $bankAccount->update([
                            'name' => $bankData['bank_name'],
                            'account_no' => $bankData['account_no'],
                        ]);
                    } else {
                        $user->bankAccounts()->create([
                            'kp_id'      => $kpId,
                            'name'       => $bankData['bank_name'],
                            'account_no' => $bankData['account_no'],
                        ]);
                    }
                } else {
                    // If the admin cleared the inputs, delete the record
                    if ($bankAccount) {
                        $bankAccount->delete();
                    }
                }
            }
        }

        $user->roles()->sync($request->input('roles', []));

        UserLogger::log(UserLogger::ACTION_UPDATE, Route::currentRouteName(), $user->id);
        return redirect()->route('user.index')->with('success', 'User updated successfully.');
    }

    /**
     * Soft-delete user (set status to deleted).
     *
     * @param  int  $id
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy(int $id)
    {
        if (!hasPermission('user.manage', PermissionAccessService::DELETE)) {
            abort(404, 'Unauthorized.');
        }

        $user = User::withTrashed()->findOrFail($id);

        $user->update([
            'status' => User::STATUS_DELETED
        ]);

        $user->delete();

        UserLogger::log(UserLogger::ACTION_DELETE, Route::currentRouteName(), $user->id);
        return redirect()->route('user.index')->with('success', 'User deleted successfully.');
    }

    /**
     * Overwite
     * Get status label HTML for a user.
     */
    protected function getStatusBadge($status)
    {
        $statuses = [
            User::STATUS_INACTIVE  => ['label' => 'Inactive',  'color' => 'secondary', 'text_color' => 'text-light',  'icon' => 'fa-power-off'],
            User::STATUS_ACTIVE    => ['label' => 'Active',    'color' => 'success',   'text_color' => 'text-light',  'icon' => 'fa-check-circle'],
            User::STATUS_DORMANT   => ['label' => 'Dormant',   'color' => 'primary',   'text_color' => 'text-light',  'icon' => 'fa-moon'],
            User::STATUS_SUSPENDED => ['label' => 'Suspended', 'color' => 'warning',   'text_color' => 'text-dark',   'icon' => 'fa-ban'],
            User::STATUS_INVITED   => ['label' => 'Invited',   'color' => 'info',      'text_color' => 'text-dark',   'icon' => 'fa-envelope-open'],
            User::STATUS_DELETED   => ['label' => 'Deleted',   'color' => 'danger',    'text_color' => 'text-light',  'icon' => 'fa-trash'],
        ];

        $info = $statuses[$status] ?? ['label' => 'Unknown', 'color' => 'dark', 'text_color' => 'text-light', 'icon' => 'fa-question-circle'];

        return <<<HTML
            <span class="badge rounded-pill bg-{$info['color']} {$info['text_color']} p-2" data-bs-toggle="tooltip" title="{$info['label']}">
                {$info['label']}
            </span>
        HTML;
    }

    /**
     * Overwite
     * Get status aku janji label HTML for a user.
     */
    protected function getStatusAkuJanjiBadge($uploaded = null)
    {
        $statuses = [
            'SUDAH'     => ['label' => 'Telah Dimuat Naik',  'color' => 'success', 'text_color' => 'text-light'],
            'BELUM'     => ['label' => 'Belum Dimuat Naik',  'color' => 'warning', 'text_color' => 'text-dark']
        ];

        $status = $uploaded ? 'SUDAH' : 'BELUM';

        $info = $statuses[$status];

        return <<<HTML
            <span class="badge rounded-pill bg-{$info['color']} {$info['text_color']} p-2" data-bs-toggle="tooltip" title="{$info['label']}">
                {$info['label']}
            </span>
        HTML;
    }

    /**
     * User for select2
     */
    public function ajaxSearch(Request $request)
    {
        $search = $request->search;

        $users = User::where('name', 'like', "%{$search}%")
            ->where('status', User::STATUS_ACTIVE)
            ->limit(40)
            ->get(['id', 'name']);

        return $users->map(function ($u) {
            return [
                'id' => $u->id,
                'text' => $u->name
            ];
        });
    }

    /**
     * Update user TnC status
     */
    public function agreeTnc(Request $request)
    {
        $value = (int) $request->input('tnc_agree', 0);

        if ($value) {
            /** @var \App\Models\User $user */
            $user = Auth::user();
            $user->update(['tnc_agree_at' => Carbon::now()]);
            session(['userTncAgree' => $value]);
            return response()->json(['success' => true]);
        }
    }

    /**
     * View user details
     */
    public function view(int $id)
    {
        if (!hasPermission('user.manage', PermissionAccessService::VIEW)) {
            abort(404, 'Unauthorized.');
        }

        $user = User::withTrashed()->findOrFail($id);
        $userId = $user->id;

        $model = PlanService::getPlanListForUser($userId);

        $totalPlan = PlanUser::query()
            ->select(['model_id'])
            ->leftJoin('plans', 'plan_user.plan_id', 'plans.id')
            ->where('user_id', $userId)
            ->groupBy('model_id')
            ->get()
            ->count();

        $kpList = PlanUser::where('user_id', $userId)
            ->join('plans', 'plans.id', '=', 'plan_user.plan_id')
            ->join('models', 'models.id', '=', 'plans.model_id')
            ->join('kps', 'kps.id', '=', 'models.kp_id')
            ->distinct()
            ->pluck('kps.name', 'kps.id');

        $totalInvestCent = PlanUser::whereHas('plan', function ($q) {
            $q->where('type', Plan::TYPE_BONDA)
            ->where('payment_type', Plan::PAYMENT_TYPE_DEBIT);
        })
        ->where('user_id', $userId)
        ->sum('investment');

        $totalRoiCent = PlanUser::whereHas('plan', function ($q) {
            $q->where('payment_type', Plan::PAYMENT_TYPE_CREDIT);
        })
        ->where('user_id', $userId)
        ->sum('investment');

        $totalPaymentMadeCent = PaymentLedger::where('user_id', $userId)
        ->sum('payment_amount');

        $totalInvest = "RM " . number_format(($totalInvestCent / 100), 2);
        $totalRoi = "RM " . number_format(($totalRoiCent / 100), 2);
        $totalPaymentMade = "RM " . number_format(($totalPaymentMadeCent / 100), 2);

        $uploadedTnC = !is_null($user->tnc_upload_at) ? true : false;

        if ($uploadedTnC) {
            $styling = [
                'label'         => 'Akuan Janji Telah Dimuat Naik',
                'color'         => 'success',
                'text_color'    => 'text-light'
            ];
        } else {
            $styling = [
                'label'         => 'Akuan Janji Belum Dimuat Naik',
                'color'         => 'warning',
                'text_color'    => 'text-dark'
            ];
        }

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName());
        return view('user.view', compact('user', 'totalPlan', 'totalInvest', 'totalRoi', 'totalPaymentMade', 'model', 'userId', 'kpList', 'styling'));
    }

    /**
     * Update user status
     */
    public function activateAccount(Request $request, int $id)
    {
        if (!hasPermission('user.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $user = User::withTrashed()->findOrFail($id);

        $validated = $request->validate([
            'status'        => 'required|in:0,1'
        ]);

        $user->update([
            'status'        => $validated['status'],
        ]);

        UserLogger::log(UserLogger::ACTION_UPDATE, Route::currentRouteName(), $user->id);

        return response()->json([
            'success' => true,
            'status'  => $validated['status']
        ]);
    }
}
