<?php

namespace App\Http\Controllers\Admin;

use App\Facades\RequestContext;
use App\Http\Controllers\Controller;
use App\Http\Requests\UserFrontendEdit;
use App\Libs\Services\BackendUserService;
use App\Libs\Services\UserFrontendService;
use App\Libs\Transformers\UserFrontend\UserFrontendTransformer;
use App\Models\Committee;
use App\Models\User;
use App\Models\WorkGroup;
use Illuminate\Http\Request;
use Spatie\Fractal\Facades\Fractal;
use Maatwebsite\Excel\Facades\Excel;
use App\Exports\UsersBackofficeExport;
use Illuminate\Support\Facades\Log;
use Illuminate\Auth\Events\Registered;

class UserFrontendController extends Controller
{
    public function getIndex(Request $request, BackendUserService $backendUserService)
    {
        $loggedUser = $backendUserService->getLoggedUser();
        $memberId = $request->input("memberId");
        $memberName = $request->input("memberName");

        $workGroups = WorkGroup::full()
            ->where('status', 'published')
            ->get();
        $workGroupsArray = [];
        foreach ($workGroups as $value) {
            $workGroupsArray[$value->id] = $value->title;
        }

        $committees = Committee::full()
            ->where('status', 'published')
            ->get();

        $committeesArray = [];
        foreach ($committees as $value) {
            $committeesArray[$value->id] = $value->title;
        }

        return view('admin.pages.users.users', [
            'loggedUser'    => $loggedUser,
            'workGroups'    => $workGroupsArray,
            'committees'    => $committeesArray,
            'memberId'      => $memberId,
            'memberName'    => $memberName,
            'canEdit'       => $loggedUser->userType->id == 1,
        ]);
    }

    public function postList(Request $request, UserFrontendService $userFrontendService)
    {
        $page = $request->input("current");
        $rowCount = $request->input("rowCount");
        $sort = $request->input("sort");
        $search = $request->input("searchPhrase");
        $status = $request->input("status");
        $wg = $request->input("wg");
        $committee = $request->input("committee");
        $memberId = $request->input("memberId");

        if (!empty($page)) {
            $result = $userFrontendService->getUserGridList($page, $rowCount, $sort, $search, $status, $wg, $committee, $memberId);
            $result["rows"] = Fractal::collection($result["rows"])
                ->transformWith(new UserFrontendTransformer())->toArray();
            return response()->json($result);
        } else {
            $users = User::all();
            return response()->json(Fractal::collection($users)
                ->transformWith(new UserFrontendTransformer())->toArray());
        }
    }

    public function getEdit($userId)
    {
        $loggedUser = BackendUserService::getLoggedUser();

        if ($loggedUser->userType->id != 1) {
            abort(403);
        }

        $permissionFinanceSubCommittee = $loggedUser->hasPermission("users.financecommittee");

        if (
            !$loggedUser->hasPermission("users.view")
            && !$loggedUser->hasPermission("users.insert")
        ) {
            abort(403);
        }

        if(empty($userId)){
            abort(404);
        }

        RequestContext::set('selected_menu', 'admin');
        RequestContext::set('selected_menu_option', 'list_users');

        $user = User::find($userId);

        if(empty($user)){
            abort(404);
        }

        $member = $user->member;
        $listCommittees = [];

        if (!empty($member)) {
            $listCommittees = Committee::whereIn('id', function ($query) use ($member) {
                $query->select('committee_id')
                        ->from('work_groups')
                        ->whereIn('work_groups.id', $member->workGroups->pluck('id')->all());
            })
            ->orWhereIn('id', function ($query) use ($member) {
                $query->select('committee_id')
                        ->from('committee_member')
                        ->whereRaw('committee_member.committee_id = committees.id')
                        ->where('committee_member.member_id', $member->id);
            })
            ->distinct()->get();
        }

        $committees = [];
        foreach ($user->committees as $committee) {
            $committees[] = ['id' => $committee->id, 'type' => $committee->pivot->type];
        }

        $workGroups = [];
        foreach ($user->workGroups as $workGroup) {
            $workGroups[] = ['id' => $workGroup->id, 'type' => $workGroup->pivot->type];
        }

        return view('admin.pages.users.user_form', [
            'listCommittees' => $listCommittees,
            'user'           => $user,
            'workGroups'     => $workGroups,
            'committees'     => $committees,
            'canManage'      => true,
            'canEdit'        => true,
            'canView'        => true,
            'permissionFinanceSubCommittee' => $permissionFinanceSubCommittee
        ]);
    }

    public function postEdit(UserFrontendEdit $request, UserFrontendService $userFrontendService, $userId)
    {
        if(empty($userId)){
            abort(404);
        }

        $data = $request->validated();

        $workGroups = $request->input('wg', []);
        $data['workGroups'] = $workGroups;

        $committees = $request->input('com', []);
        $data['committees'] = $committees;

        $typesWorkGroups = $request->input('wg_type', []);
        $data['typesWorkGroups'] = $typesWorkGroups;

        $typesCommittees = $request->input('com_type', []);
        $data['typesCommittees'] = $typesCommittees;

        if(count($workGroups) !== count($typesWorkGroups)) {
            $message = "Form with errors";
            return redirect('/admin/users-frontend/edit/' . $userId, 302)
                ->with("globalErrorMessage", $message)
                ->with("errorMessage", $message);
        }

        if(count($committees) !== count($typesCommittees)) {
            $message = "Form with errors";
            return redirect('/admin/users-frontend/edit/' . $userId, 302)
                ->with("globalErrorMessage", $message)
                ->with("errorMessage", $message);
        }

        $user = $userFrontendService->editUser($userId, $data);
        $message = "User updated";

        return redirect('/admin/users-frontend/edit/' . $user->id)
            ->with("message", $message);
    }

    public function getExportUsers(Request $request)
    {
        // Increase execution time and memory limits for large datasets
        ini_set('max_execution_time', 600); // 10 minutes
        ini_set('memory_limit', '1024M'); // 1GB

        // Force garbage collection and clear any potential memory issues
        if (function_exists('gc_collect_cycles')) {
            gc_collect_cycles();
        }

        $status = $request->input("status");
        $wg = $request->input("wg");
        $committee = $request->input("committee");
        $memberId = $request->input("memberId");

        try {
            // Estimate dataset size for monitoring
            $userQuery = User::query();
            if (!empty($status)) {
                $userQuery->where('state', $status);
            }
            if (!empty($wg) && $wg > 0) {
                $userQuery->whereHas('workGroups', function($q) use ($wg) {
                    $q->where('work_groups.id', $wg);
                });
            }
            if (!empty($committee) && $committee > 0) {
                $userQuery->whereHas('committees', function($q) use ($committee) {
                    $q->where('committees.id', $committee);
                });
            }
            if (!empty($memberId)) {
                $userQuery->where('member_id', $memberId);
            }

            $estimatedCount = $userQuery->count();

            Log::info('User export started', [
                'status' => $status,
                'workgroup' => $wg,
                'committee' => $committee,
                'member_id' => $memberId,
                'estimated_records' => $estimatedCount,
                'memory_limit' => ini_get('memory_limit'),
                'time_limit' => ini_get('max_execution_time')
            ]);

            $startTime = microtime(true);
            $startMemory = memory_get_usage(true);

            $response = Excel::download(new UsersBackofficeExport($status, $wg, $committee, $memberId), 'users.xlsx');

            $endTime = microtime(true);
            $endMemory = memory_get_usage(true);
            $peakMemory = memory_get_peak_usage(true);

            Log::info('User export completed successfully', [
                'execution_time' => round($endTime - $startTime, 2) . 's',
                'memory_used' => round(($endMemory - $startMemory) / 1024 / 1024, 2) . 'MB',
                'peak_memory' => round($peakMemory / 1024 / 1024, 2) . 'MB',
                'estimated_records' => $estimatedCount
            ]);

            return $response;

        } catch (\Exception $e) {
            Log::error('User export failed', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'memory_usage' => round(memory_get_usage(true) / 1024 / 1024, 2) . 'MB',
                'peak_memory' => round(memory_get_peak_usage(true) / 1024 / 1024, 2) . 'MB'
            ]);

            return response()->json([
                'error' => 'Export failed. Please try again or contact support.',
                'message' => config('app.debug') ? $e->getMessage() : 'Internal server error'
            ], 500);
        } finally {
            // Clean up memory
            if (function_exists('gc_collect_cycles')) {
                gc_collect_cycles();
            }
        }
    }

    public function postDelete(Request $request)
    {
        $id = $request->input("id");
        $user = User::find($id);

        if(!empty($user)){
            $user->delete();
        }

        return response()->json(["success" => true]);
    }

    public function postResend(Request $request) {
        $id = $request->input("id");
        $user = User::find($id);

        event(new Registered($user));
    }
}
