<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use App\Models\UserType;
use App\Models\AssetHistory;
use App\Http\Requests\StoreUser;
use App\Http\Requests\UpdateUser;
use App\Models\SoftwareLicense\SoftwareLicenseHistory;
use App\Services\User\UserData;
use Facades\App\Services\ExportManagement\ExportManagementService;
use App\Http\Traits\UserDataFetcherTrait;
use App\Http\Responses\ReportJsonResponse;
use App\Services\User\UserService;
use App\Models\IntegrationSyncHistory;

class UserController extends Controller
{
    use UserDataFetcherTrait;

    /**
     * Constructs a new instance of the usercontroller class.
     *
     * @param UserData $userData The user data.
     * @param UserService $userService The user service.
     */
    public function __construct(protected UserData $userData, protected UserService $userService) {}

    /**
     * Retrieves the index view for the users.
     *
     * @throws Some_Exception_Class description of exception
     * @return Some_Return_Value
     */
    public function index()
    {
        $lastSync = IntegrationSyncHistory::getLastSync(config('integration-sync-histories.users'))->first();

        $lastSyncDate = $lastSync?->created_at;

        return view('users.index', compact('lastSyncDate'));
    }

    /**
     * Retrieves and displays detailed information about a user.
     *
     * @param mixed $user The user ID or object.
     * @throws Exception If the user cannot be found.
     * @return \Illuminate\Contracts\View\View The view for the user detail page.
     */
    public function show($user)
    {
        $uid = $user;
        $user = User::with('assets.assetType', 'assets.makeAndModel.manufacturer', 'assets.technicalSpec', 'assets.assetStatus', 'userLicense.license.softwareLicenseManufacturer')->find($user);
        $softwareLicenceHistory = SoftwareLicenseHistory::with('SoftwareLicense')->where('license_user_id', $uid)->get();

        return view('users.detail', compact('user', 'softwareLicenceHistory'));
    }

    /**
     * Create a new user.
     *
     * @return \Illuminate\View\View
     */
    public function create()
    {
        $userRoles = UserType::userRoles()->orderBy('name')->get();
        session(['count_add' => 0]);
        return view('users.create', compact('userRoles'));
    }

    /**
     * Edits the user.
     *
     * @param mixed $user The user to edit.
     * @throws Some_Exception_Class If there is an exception.
     * @return \Illuminate\Contracts\View\Factory|\Illuminate\View\View The view for editing the user.
     */
    public function edit($user)
    {
        $user = User::with('assets', 'assets.makeAndModel', 'assets.makeAndModel.manufacturer', 'assets.assetType', 'assets.assetStatus', 'position')->find($user);
        $userType = optional($user->userType)->name;
        return view('users.edit', compact('user', 'userType'));
    }

    /**
     * Store the user data.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function store()
    {
        $userMeta = request()->all();

        if (!isset($userMeta['first_name'])) {
            return redirect(route('users.create'))->withError('Nothing to save.');
        }

        $errors = $this->userService->storeUsers($userMeta);

        if (!empty($errors)) {
            array_unshift($errors, 'User Created With Errors');
            return redirect(route('users.create'))->withErrors($errors);
        }
        session(['count_add' => 0]);
        return redirect(route('users.index'))->with('message', __('message.user_created'));
    }

    /**
     * Update a user.
     *
     * @param UpdateUser $request The request object.
     * @param mixed $user The user ID.
     * @return Illuminate\Http\RedirectResponse Redirects to the users index page.
     */
    public function update(UpdateUser $request, $user)
    {
        $userData = User::with('assets', 'userType')->find($user);
        $request = [
            'user_type_id' => request('user_type_id'),
        ];

        if ($userData->userType) {
            $userData->removeRole(optional($userData->userType)->name);
        }

        $userData = User::findOrFail($user)->update($request);
        $userData = User::find($user);
        if ($userData->userType) {
            if (!$userData->hasRole(optional($userData->userType)->name)) {
                $userData->assignRole(optional($userData->userType)->name);
            }
        }

        return redirect(route('users.index'))->with('message', __('message.user_updated'));
    }

    /**
     * Adds a new row user to the preview.
     *
     * @param StoreUser $request the request object containing the user data
     * @param int $count (optional) the number of times the user is being added (default: 1)
     * @throws Some_Exception_Class description of exception
     * @return \Illuminate\Http\JsonResponse the JSON response containing the added user's information or an error message
     */
    public function add(StoreUser $request, $count = 1)
    {

        $existUser = User::where('email', $request['email'])->first();
        if (!$existUser) {
            if (session('count_add')) {
                $count = session('count_add') + 1;
            }
            session(['count_add' => $count]);
            $request['count_add'] = session('count_add');
            $view = view('users.partials.added-users', compact('request'))->render();
            return response()->json($view);
        }
        return response()->json(['error' => 'Email already exists']);
    }

    /**
     * Retrieves data and returns it as JSON.
     *
     * @param Request $request The HTTP request object.
     * @throws Some_Exception_Class description of exception
     * @return void
     */
    public function data(Request $request)
    {
        $filteredData = $this->userData->getData();
        $users =  $filteredData['users'];

        $start = request('start');
        $data = [];

        if (!empty($users)) {
            $data = $this->userData->getUserData($users, $start, $data);
        }

        return new ReportJsonResponse($request->input('draw'), $data, $filteredData['count']);
    }

    /**
     * Handles the user export
     * @return [type]
     */
    public function export()
    {
        setUnlimitedExecutionTimeAndMemoryLimit();

        $filteredData = $this->userData->getExportData();
        if (ExportManagementService::userLargeExport($filteredData)) {
            return 'Your report will be generated in the background. Go to the <a href="/generated-exports/user_report" target="_blank">Reports Page</a> to download the report.';
        }

        $datas = collect();
        $data = [];

        $datas->push($this->userData->getExportUserData($filteredData->get(), 0, $data));

        return exportToCsv($datas->toArray());
    }
}
