<?php

namespace App\Http\Controllers;

use App\Actions\Fortify\UpdateUserProfileInformation;
use App\Http\Helpers\FileUploader;
use App\Http\Helpers\UploadedFiles;
use App\Models\Engineer;
use App\Models\Firm;
use App\Models\Language;
use App\Models\LanguageProficiency;
use App\Models\LevelOfExperience;
use App\Models\Service;
use App\Models\User;
use App\Notifications\CompleteRegistration;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Crypt;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Laravel\Jetstream\Jetstream;
use Rinvex\Categories\Models\Category;

class EngineerController extends Controller
{
    public function index(Request $request)
    {
        if ($request->has('search')) {
            return Engineer::search($request->search)->paginate(20);
        }
        return Engineer::paginate(20);
    }

    public function show($slug = null)
    {

        $slug = $slug ?? Auth::user()->engineer?->slug;
        $engineer = Engineer::with(['user', 'location', 'LevelOfExperience',
            'skills', 'experiences', 'educations', 'certificates',
            'portfolioProjects.skills', 'portfolioProjects.images',
            'categories', 'phone', 'workRates.rateable',
            'workRates.user',
            ])->where('slug', $slug)->firstOrFail();

            $services = Service::where('status', 'Published')
            ->where('serviceable_id', $engineer->id)
            ->where('serviceable_type', 'App\Models\Engineer')
            ->with(
                "images",
                "skills",
                "location",
                "tierOptions",
                "orders",
                "serviceable.user"
                )
            ->paginate(10);

            // dd($services);

        return Inertia::render('Dashboard/Engineer/Index', ['engineer' => $engineer, 'services' => $services]);

    }

    public function settings()
    {
        $slug = Auth::user()->engineer?->slug;
        $levelsOfExperience = LevelOfExperience::all();
        $languages = Language::all();
        $proficiencies = LanguageProficiency::all();
        $categories = Category::where('parent_id', null)->with('descendants')->get();
        $engineer = Engineer::with('user', 'location', 'LevelOfExperience', 'skills', 'experiences', 'educations', 'certificates', 'portfolioProjects.skills', 'portfolioProjects.images', 'categories', 'phone', 'rates')->where('slug', $slug)->firstOrFail();
        return Inertia::render('Settings/Engineer/Show', ['engineer' => $engineer, 'levelsOfExperience' => $levelsOfExperience, 'languages' => $languages, 'proficiencies' => $proficiencies, 'categories' => $categories,]);

    }

    public function getRates(Engineer $engineer)
    {
        return $engineer->workRates()->get();
    }

    public function complete(Engineer $engineer)
    {
        try {

            if ($engineer->verificationRequests->where('action', null)->count() > 0) {
                session()->flash('success', "You have a verification request in progress we will back to you once we have updates, thanks for your patience");
            } else {
                $engineer->verificationRequests()->create([]);
                session()->flash('success', "Your profile has been submitted for review, we'll get back to you shortly");
            }
            return back(303);
        } catch (Exception $e) {

        }
    }

    public function addExperience(Request $request)
    {
        $experience = $request->validate(['title' => 'required|string', 'company_name' => 'required|string', 'location' => 'required|string', 'start_date' => 'required|date', 'currently_working_here' => 'required|boolean', 'end_date' => 'nullable|required_if:currently_working_here,false|date',]);

        $experience['start_date'] = Carbon::parse($experience['start_date']);

        if (!$experience['currently_working_here']) {

            $experience['end_date'] = Carbon::parse($experience['end_date']);

        }

        $engineer = Auth::user()->engineer;

        $engineer->experiences()->create($experience);

        return back(303)->with(['success' => 'success']);
    }

    public function addEducation(Request $request)
    {
        $education = $request->validate(['school' => 'required|string', 'degree' => 'required|string', 'start_date' => 'required|date', 'end_date' => 'required|date',]);

        $education['start_date'] = Carbon::parse($education['start_date']);

        $education['end_date'] = Carbon::parse($education['end_date']);

        $engineer = Auth::user()->engineer;

        $engineer->educations()->create($education);

        return back(303)->with(['success' => 'success']);
    }

    public function addMastery(Request $request)
    {
        $language = $request->validate(['language_id' => ['required', Rule::exists('languages', 'id')], 'proficiency_id' => ['required', Rule::exists('language_proficiencies', 'id')],]);

        $engineer = Auth::user()->engineer;

        $engineer->addMastery($language['language_id'], $language['proficiency_id']);

        return back(303)->with(['success' => 'success']);
    }

    public function updateMastery(Request $request)
    {
        // dd($request->all());
        $language = $request->validate(['id' => ['required', Rule::exists('languagables', 'id')], 'language_id' => ['required', Rule::exists('languages', 'id')], 'proficiency_id' => ['required', Rule::exists('language_proficiencies', 'id')],]);

        $engineer = Auth::user()->engineer;

        $engineer->updateMastery($language['id'], $language['language_id'], $language['proficiency_id']);

        return back(303)->with(['success' => 'success']);
    }

    public function destroyMastery(Request $request)
    {
        $language = $request->validate(['id' => ['required', Rule::exists('languagables', 'id')],]);

        $engineer = Auth::user()->engineer;

        $engineer->removeMastery($language['id']);

        return back(303)->with(['success' => 'success']);
    }

    public function addCertificate(Request $request)
    {
        $certificate = $request->validate([

            'name' => 'required|string',

            'issuing_org' => 'required|string',

            'credential_url' => 'required|string',

            'does_not_expire' => 'required|boolean',

            'credential_id' => 'required|string',

            'start_date' => 'required|date',

            'end_date' => 'nullable|required_if:does_not_expire,false|date',

        ]);


        $certificate['start_date'] = Carbon::parse($certificate['start_date']);

        if (!$certificate['does_not_expire']) {

            $certificate['end_date'] = Carbon::parse($certificate['end_date']);

        }

        $engineer = Auth::user()->engineer;

        $engineer->certificates()->create($certificate);

        return back(303)->with(['success' => 'success']);
    }

    public function addPortfolioProject(Request $request)
    {
        $engineer = Auth::user()->engineer;
        return $engineer->createPortfolio($request);
    }

    public function destroy(Engineer $engineer)
    {
        $engineer->delete();
        return back(303)->with(['success' => 'success']);
    }

    public function update(Request $request)
    {
        $engineer = Auth::user()->engineer;
        try {
            $transaction = DB::transaction(function () use ($request, $engineer) {
                $attrs = $this->validateEngineerRequest($request, true);

                if ($request->has('sub_categories')) {
                    $engineer->categories()->sync($request->sub_categories);
                }

                if ($request->has('skills')) {
                    $engineer->skills()->sync($request->skills);
                }

                if ($request->has('location')) {
                    $engineer->addLocation($request->location);
                }

                if ($request->has('phone')) {
                    $engineer->addPhone($request->phone);
                }

                if ($request->has('social_links')) {
                    $engineer->addSocials($request->social_links);
                }

                if ($request->has('slug')) {
                    $attrs['slug'] = strtolower($attrs['slug']);
                }

                if ($request->hasFile('engineering_licence')) {
                    $attrs['engineering_licence_path'] = FileUploader::store('engineering_licences/', $request->file('engineering_licence'));
                }

                if ($request->hasFile('engineering_degree')) {
                    $attrs['engineering_degree_path'] = FileUploader::store('engineering_degrees/', $request->file('engineering_degree'));
                }

                if ($request->hasFile('engineering_licence')) {
                    $attrs['passport_path'] = FileUploader::store('passports/', $request->file('passport'));
                }

                if ($request->hasFile('engineering_licence')) {
                    $attrs['cv_path'] = FileUploader::store('cvs/', $request->file('cv'));
                }

                if($request->hasFile('photo')){
                    $attrs['profile_photo_path'] = FileUploader::store('photos/', $request->file('photo'));
                    $engineer->user->forceFill([
                        'profile_photo_path' => $attrs['profile_photo_path'],
                    ])->save();
                }

                if($request->hasFile('cover_photo')){
                    $engineer->user->forceFill([
                        'cover_photo_path' => FileUploader::store('photos/', $request->file('cover_photo')),
                    ])->save();
                }

                $engineer->update($attrs);
                $usrData=[];
                if($request->email){
                    $usrData['email']=$request->email;
                }
                if($request->name){
                    $usrData['name']=$request->name;
                }
                if($request->tag_line){
                    $usrData['tag_line']=$request->tag_line;
                }
                UpdateUserProfileInformation::updateUser(Auth::user(),$usrData);
                $engineer->save();
                $engineer->searchable();
            });
            return is_null($transaction) ? back(303)->with(['success' => 'success']) : $transaction;
        } catch (Exception $exception) {
            return back(303)->with(['error' => $exception->getMessage()]);
        }

    }

    /**
     * @param Request $request
     * @return array
     */
    protected function validateEngineerRequest(Request $request, ?bool $update = false): array
    {
        $request->validate(
            ['skills' => [$update ? 'nullable' : 'required', 'array'], 'skills.*' => ['integer', Rule::exists('skills', 'id')], 'engineering_licence' => UploadedFiles::getRules(true), 'engineering_degree' => UploadedFiles::getRules(true), 'passport' => UploadedFiles::getRules(true), 'cv' => UploadedFiles::getRules(true), 'social_links' => 'nullable', 'sub_categories' => [$update ? 'nullable' : 'required', 'array'], 'sub_categories.*' => ['integer', Rule::exists('categories', 'id')], 'location.long' => $update ? 'nullable' : 'required', 'location.lat' => $update ? 'nullable' : 'required', 'location.address' => $update ? 'nullable' : 'required', 'phone.number' => $update ? 'nullable' : 'required', 'phone.code' => $update ? 'nullable' : 'required']);
        return $request->validate(
            ['name' => $update ? 'nullable' : 'required|string',
                'email' => $update ? 'nullable' : 'required|unique:engineers,email|email|unique:users,email',
                'tag_line' => $update ? 'nullable' : 'required', 'about' => $update ? 'nullable' : 'required', 'level_of_experience_id' => [$update ? 'nullable' : 'required', Rule::exists('level_of_experiences', 'id')], 'daily_rate' => $update ? 'nullable' : 'required', 'monthly_rate' => $update ? 'nullable' : 'required', 'yearly_rate' => $update ? 'nullable' : 'required', 'category_id' => [$update ? 'nullable' : 'required', Rule::exists('categories', 'id')], 'engineering_licence_number' => 'nullable|unique:engineers,engineering_licence_number', 'slug' => $update ? ['nullable', Rule::unique('engineers')->ignore(Auth::user()->engineer->slug, 'slug')] : 'prohibited',]);
    }

    public function store(Request $request)
    {
        try {
            $slug = null;
            $transaction = DB::transaction(function () use ($request, $slug) {
                $attr = $this->validateEngineerRequest($request);
                //create location database row
                $user = User::create(["name" => $request->name, "email" => $request->email,]);
                //create the engineer request
                $engineer = Engineer::create(array_merge($attr, ['engineering_licence_path' => $request->hasFile('engineering_licence_path') ? FileUploader::store('engineering_licences/', $request->file('engineering_licence')) : null, 'engineering_degree_path' => $request->hasFile('engineering_degree_path') ? FileUploader::store('engineering_degrees/', $request->file('engineering_degree')) : null, 'passport_path' => $request->hasFile('passport_path') ? FileUploader::store('passports/', $request->file('passport')) : null, 'cv_path' => $request->hasFile('cv') ? FileUploader::store('cvs/', $request->file('cv')) : null, 'user_id' => $user->id,]));
                //attach the data to the engineer

                if($user->wallet !=null){
                    $wallet= $user->wallet;
                    $wallet->update([
                        'owner_id'=>$engineer->id,
                        'owner_type'=> 'App\Models\Engineer'
                    ]);
                    $user->wallet()->delete();
                    $user->save();
                    $wallet->save();
                }else{
                    $engineer->wallet()->create();
                }
                $engineer->addLocation($request->location);
                $engineer->skills()->attach($request->skills);
                if ($request->social_links) $engineer->addSocials($request->social_links);
                $engineer->categories()->attach($request->sub_categories);
                $engineer->addPhone($request->phone);

                // TODO:: add the currency of the engineer
                $engineer->addCurrency(1);

                $engineer->save();

                $engineer->searchable();
                $engineer->notify(new CompleteRegistration(Crypt::encryptString($engineer->email),'engineer'));
                return $engineer;
            });

            // dd($transaction);



            return !is_null($transaction) ? redirect()->route('complete.registration', [
                'type' => 'engineer',
                'id' => Crypt::encryptString($transaction->email)
            ]) : $transaction;
        } catch (Exception $exception) {
            return back(303)->with(['error' => $exception->getMessage()]);
        }
    }
}
