<?php

namespace App\Http\Controllers;

use App\Exports\PlanSummaryExport;
use App\Models\KP;
use App\Models\Model;
use App\Models\Plan;
use App\Models\User;
use App\Services\PermissionAccessService;
use App\Services\PlanService;
use App\Services\UserLogger;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;
use Illuminate\Validation\ValidationException;
use Maatwebsite\Excel\Facades\Excel;
use Throwable;
use Yajra\DataTables\Facades\DataTables;

class PlanController extends Controller
{
    private function queryForListing($kpID, $userID)
    {
        $query = Model::query()
            ->leftJoin('plans', 'plans.model_id', '=', 'models.id')
            ->leftJoin('plan_user', 'plan_user.plan_id', '=', 'plans.id')
            ->leftJoin('kps', 'kps.id', '=', 'models.kp_id')
            ->select([
                'models.*',

                DB::raw("
                    SUM(
                        CASE WHEN plans.type = " . Plan::TYPE_KP . " AND  plans.payment_type = " . Plan::PAYMENT_TYPE_CREDIT . "
                        THEN plan_user.investment ELSE 0 END
                    ) AS total_po_kp
                "),

                DB::raw("
                    SUM(
                        CASE WHEN plans.type = " . Plan::TYPE_BONDA . " AND  plans.payment_type = " . Plan::PAYMENT_TYPE_CREDIT . "
                        THEN plan_user.investment ELSE 0 END
                    ) AS total_po_bonda
                "),

                DB::raw("
                    SUM(
                        CASE WHEN plans.payment_type = " . Plan::PAYMENT_TYPE_DEBIT . "
                        THEN plan_user.investment ELSE 0 END
                    ) AS total_modal
                "),

                "kps.name as kp_name",
            ])
            ->whereNull('models.deleted_at')
            ->orderByRaw('models.start_on IS NULL ASC')
            ->orderBy('models.start_on', 'ASC')
            ->groupBy('models.id');

        $query->withTrashed();

        if ($kpID !== null && is_numeric($kpID)){
            $query->where('kps.id', $kpID);
        }

        if ($userID !== null && is_numeric($userID)){
            $query->where('plan_user.user_id', $userID);
        }

        return $query;
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::VIEW)) {
            abort(404, 'Unauthorized.');
        }

        if ($request->ajax()) {


            $editPermission = hasPermission('plan.manage', PermissionAccessService::UPDATE)? '' : 'disabled';
            $deletePermission = hasPermission('plan.manage', PermissionAccessService::DELETE)? '' : 'disabled';

            $query = $this->queryForListing($request->input('kp'), $request->input('userID'));

            $query->orderByRaw('models.start_on IS NULL ASC')
                    ->orderBy('models.start_on', 'ASC');

            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('models.name', 'like', "%{$search}%")
                            ->orWhere('kps.name', 'like', "%{$search}%");
                        });
                    }
                })
                ->editColumn('created_at', function ($model) {
                    return $model->created_at_formatted;
                })
                ->addColumn('status_label', function ($model) {
                    return $this->getStatusBadge($model->status);
                })
                ->addColumn('total_po_kp', function ($model) {
                    return "RM " . number_format(((float) $model->total_po_kp / 100), 2);
                })
                ->addColumn('total_po_bonda', function ($model) {
                    return "RM " . number_format(((float) $model->total_po_bonda / 100), 2);
                })
                ->addColumn('total_modal', function ($model) {
                    return "RM " . number_format(((float) $model->total_modal / 100), 2);
                })
                ->addColumn('kp_name', function ($model) {
                    return $model->kp_name;
                })
                ->addColumn('action', function ($model) use ($editPermission, $deletePermission){
                    $viewUrl = route('plan.show', $model->id);
                    $editUrl = route('plan.edit', $model->id);
                    $deleteUrl = route('plan.destroy', $model->id);
                    $OthersBtn = view('partials.additional-action-btn', [
                        'url' => route('plan.downloadExcel', $model->id),
                        'class' => 'btn-success',
                        'title' => 'Muat turun Excel',
                        'icon' => '<i class="fa-solid fa-file-excel"></i>',
                    ])->render();

                    $isDeleted = $model->trashed();
                    return view('partials.actions-buttons', compact('viewUrl', 'editUrl', 'deleteUrl', 'editPermission', 'deletePermission', 'isDeleted', 'OthersBtn'))->render();
                })
                ->rawColumns(['status_label', 'action'])
                ->make(true);
        }

        $kpList = KP::query()->distinct()->pluck('name', 'id');

        // dd($kpList);

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName());
        return view('plan.index', compact('kpList'));
    }

    public function dataTableForUserDetails(Request $request)
    {
        if ($request->ajax()) {
            $query = $this->queryForListing($request->input('kp'), $request->input('userID'));

            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('models.name', 'like', "%{$search}%")
                            ->orWhere('kps.name', 'like', "%{$search}%");
                        });
                    }
                })
                ->editColumn('created_at', function ($model) {
                    return $model->created_at_formatted;
                })
                ->addColumn('start_on', function ($model) {
                    return $model->start_on ? \Carbon\Carbon::parse($model->start_on)->format('d M Y') : '-';
                })
                ->addColumn('end_on', function ($model) {
                    return $model->end_on ? \Carbon\Carbon::parse($model->end_on)->format('d M Y') : '-';
                })
                ->addColumn('status_label', function ($model) {
                    return $this->getStatusBadge($model->status);
                })
                ->addColumn('total_po_kp', function ($model) {
                    return "RM " . number_format(((float) $model->total_po_kp / 100), 2);
                })
                ->addColumn('total_po_bonda', function ($model) {
                    return "RM " . number_format(((float) $model->total_po_bonda / 100), 2);
                })
                ->addColumn('total_modal', function ($model) {
                    return "RM " . number_format(((float) $model->total_modal / 100), 2);
                })
                ->addColumn('kp_name', function ($model) {
                    return $model->kp_name;
                })
                ->addColumn('action', function ($model) use ($request){
                    $viewUrl = route('plan.member.show', ['id' => $model->id, 'userId' => $request->input('userID')]);

                    $OthersBtn =
                        view('partials.additional-action-btn', [
                            'url' => route('plan.member.payments', ['id' => $model->id, 'userId' => $request->input('userID')]),
                            'class' => 'btn-success',
                            'title' => 'View Payment History',
                            'icon' => '<i class="fa-solid fa-file-invoice-dollar"></i>',
                        ])->render();

                    if($request->input('key') == "cce764c0-bd08-4313-a6a8-16ed0bb80358"){

                        $OthersBtn .= view('partials.additional-action-btn', [
                            'url' => route('plan.member.updatePayment', ['id' => $model->id, 'userId' => $request->input('userID')]),
                            'class' => 'btn-warning',
                            'title' => 'Create Payment',
                            'icon' => '<i class="fas fa-edit fa-fw"></i>',
                        ])->render();
                    }

                    return view('partials.actions-buttons', compact('viewUrl', 'OthersBtn'))->render();
                })
                ->rawColumns(['status_label', 'action'])
                ->make(true);
        } else {
            abort(404, 'Unauthorized.');
        }
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        if (!hasPermission('plan.manage', PermissionAccessService::CREATE)) {
            abort(404, 'Unauthorized.');
        }

        $statuses = Model::getStatusOptions();
        $kpList = KP::query()->pluck('name', 'id');
        $planType = Plan::getTypeOptions();
        $planPaymentType = Plan::getPaymentTypeOptions();

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName());
        return view('plan.create', compact('statuses', 'planType', 'planPaymentType', 'kpList'));
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(Request $request)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::CREATE)) {
            abort(404, 'Unauthorized.');
        }

        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'status' => 'required|in:' . implode(",", [Model::STATUS_ACTIVE, Model::STATUS_INACTIVE]),
            'description' => 'nullable|string',
            'start_on' => 'nullable|date',
            'end_on' => 'nullable|date',

            // plans
            'planName'              => 'required|array|min:1',
            'planName.*'            => 'string|max:100',
            'planType'   => 'required|array',
            'planType.*' => 'in:' . implode(",", [Plan::TYPE_KP, plan::TYPE_BONDA]),
            'planPaymentType'   => 'required|array',
            'planPaymentType.*' => 'in:' . implode(",", [Plan::PAYMENT_TYPE_CREDIT, plan::PAYMENT_TYPE_DEBIT]),
        ]);

        if (count($validated['planName']) !== count($validated['planType']) && count($validated['planType']) !== count($validated['planPaymentType'])) {
            return back()->withErrors(['name' => 'Name and Type and Payment Type count mismatch.']);
        }

        try {
            DB::beginTransaction();

            $model = Model::create([
                'name'        => $validated['name'],
                'status'      => $validated['status'],
                'description' => $validated['description'],
                'start_on' => $validated['start_on'],
                'end_on' => $validated['end_on'],
            ]);

            // Prepare participants + investments
            foreach ($validated['planName'] as $index => $planName) {
                Plan::create([
                    'name'         => $planName,
                    'model_id'     => $model->id,
                    'type'         => $validated['planType'][$index],
                    'payment_type' => $validated['planPaymentType'][$index],
                ]);
            }

            UserLogger::log(UserLogger::ACTION_CREATE, Route::currentRouteName(), $model->id);

            DB::commit();
            return redirect()->route('plan.index')->with('success', 'Model created successfully.');
        } catch (Throwable $th) {
            DB::rollBack();
            return redirect()->back()->withErrors('Create failed: ' . $th->getMessage());
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::VIEW)) {
            abort(404, 'Unauthorized.');
        }

        $model = Model::findOrFail($id);
        $planType = Plan::getTypeOptions();
        $planPaymentType = Plan::getPaymentTypeOptions();

        $usersWithPlan = PlanService::getUserWithPlan($model);

        $statuses = Model::getStatusOptions();

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName(), $id);
        return view('plan.view', compact('model', 'statuses', 'planType', 'planPaymentType', 'usersWithPlan'));
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $model = Model::with('kp')->findOrFail($id);
        $kpList = KP::query()->pluck('name', 'id');
        $planType = Plan::getTypeOptions();
        $planPaymentType = Plan::getPaymentTypeOptions();

        $statuses = Model::getStatusOptions();

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName(), $id);
        return view('plan.edit', compact('model', 'statuses', 'planType', 'planPaymentType', 'kpList'));
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $validated = $request->validate([
            'name' => 'required|string|max:255',
            'status' => 'required|in:' . implode(",", [Model::STATUS_ACTIVE, Model::STATUS_INACTIVE]),
            'description' => 'nullable|string',
            'kpId' => 'required|int',
            'start_on' => 'nullable|date',
            'end_on' => 'nullable|date',
        ]);

        $model = Model::with('kp')->findOrFail($id);

        try {
            DB::beginTransaction();

            $model->update([
                'name'        => $validated['name'],
                'status'      => $validated['status'],
                'description' => $validated['description'],
                'kp_id'       => $validated['kpId'],
                'start_on'    => $validated['start_on'],
                'end_on'      => $validated['end_on'],
            ]);

            UserLogger::log(UserLogger::ACTION_UPDATE, Route::currentRouteName(), $id);

            DB::commit();
            return redirect()->route('plan.index')->with('success', 'Model updated successfully.');
        } catch (Throwable $th) {
            DB::rollBack();
            return redirect()->back()->withErrors('Updated failed: ' . $th->getMessage());
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::DELETE)) {
            abort(404, 'Unauthorized.');
        }

        $plan = Model::findOrFail($id);

        $plan->update([
            'status' => Model::STATUS_DELETED
        ]);

        $plan->delete();

        UserLogger::log(UserLogger::ACTION_DELETE, Route::currentRouteName(), $id);
        return back()->with('success', 'Model deleted successfully.');
    }

    public function editParticipant(int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $model = Model::findOrFail($id);
        $users = User::query()->limit(40)->pluck('name', 'id');

        $usersWithPlan = PlanService::getUserWithPlan($model);

        // dd($usersWithPlan);

        UserLogger::log(UserLogger::ACTION_VIEW, Route::currentRouteName(), $id);
        return view('plan.participant', compact('model', 'users', 'usersWithPlan'));
    }

    public function updateParticipant(Request $request, int $id)
    {
        if (!hasPermission('plan.manage', PermissionAccessService::UPDATE)) {
            abort(404, 'Unauthorized.');
        }

        $validated = $request->validate([
            'plan' => 'required|array',
            'plan.*' => 'required|array',
            'plan.*.*' => 'required|numeric|min:0',
        ]);

        // Validate plan_id exist
        $planIds = array_keys($validated['plan']);

        $existingPlanIds = Plan::WhereIn('id', $planIds)
            ->pluck('id')
            ->toArray();

        if (count($existingPlanIds) !== count($planIds)) {
            throw ValidationException::withMessages([
                'plan' => 'One or more plan IDs do not exist.',
            ]);
        }

        // Validate user_id exist
        foreach ($validated['plan'] as $planId => $users) {
            $userIds = array_keys($users);

            $existingUserIds = User::whereIn('id', $userIds)
                ->pluck('id')
                ->toArray();

            if (count($existingUserIds) !== count($userIds)) {
                throw ValidationException::withMessages([
                    "plan.$planId" => "One or more users do not exist for plan ID $planId.",
                ]);
            }
        }

        $model = Model::findOrFail($id);

        try {
            DB::beginTransaction();

            foreach ($model->plans as $plan) {
                $userInvests = $validated['plan'][$plan->id];

                if (!count($userInvests)) continue;

                $participantsWithPivot = [];
                foreach ($userInvests as $userId => $invest) {
                    $participantsWithPivot[$userId] = [
                        'investment' => $invest
                    ];
                }

                $plan->users()->sync($participantsWithPivot);
            }

            UserLogger::log(UserLogger::ACTION_UPDATE, Route::currentRouteName(), $id);

            DB::commit();
            return redirect()->route('plan.index')->with('success', 'Model updated successfully.');
        } catch (Throwable $th) {
            DB::rollBack();
            return redirect()->back()->withErrors('Updated failed: ' . $th->getMessage());
        }
    }

    public function showPlanForUser($id, $userId = null)
    {
        $userId = $userId ?? Auth::id();

        if (!hasPermission('plan.manage', PermissionAccessService::VIEW) && !($userId == Auth::id())) {
            abort(404, 'Unauthorized.');
        }

        $model = PlanService::getPlanForUser($id, $userId);

        if (empty($model)) {
            abort(404, 'Not Found!.');
        }

        return view('plan.member', compact('model'));
    }

    public function downloadExcel($id)
    {
        return Excel::download(
            new PlanSummaryExport((int) $id),
            'plan-summary-' . $id . '.xlsx'
        );
    }

    public function downloadMasterListPDF()
    {
        $query = $this->queryForListing(null, Auth::id());
        $listOfPlan = $query->get();

        /** @var User $user */
        $user = Auth::user();

        $path = public_path('img/logo-gtbz-120.png');
        $image_data = file_get_contents($path);
        $base64_image = base64_encode($image_data);

        $bankAccount = $user->bankAccounts()
            ->get(['kp_id', 'name', 'account_no'])
            ->keyBy('kp_id')
            ->toArray();

        $pdf = Pdf::loadView('pdf.gtbz-summary', [
            'user' => $user,
            'bankAccount' => $bankAccount,
            'plans' => $listOfPlan,
            'base64_image' => $base64_image
        ])->setPaper('a4', 'landscape');;

        return $pdf->stream('gtbz-summary.pdf');
    }
}
