<?php

namespace App\Http\Controllers;

use App\Filters\ServiceFilters;
use App\Http\Helpers\FileUploader;
use App\Http\Helpers\UploadedFiles;
use App\Models\Service;
use App\Models\ServiceImage;
use App\Models\ServiceOrder;
use App\Models\ServiceTierOption;
use App\Models\Skill;
use App\Models\User;
use Carbon\Carbon;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Inertia\Inertia;
use Rinvex\Categories\Models\Category;

class ServiceController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index(Request $request, ServiceFilters $filters)
    {
        $categories = Category::where("parent_id", null)
        ->with("descendants")
        ->get();

        $skills = Skill::where("verified", 1)->get();

        $services = Service::filter($filters)
        ->with(
            "images",
            "skills",
            "location",
            "tierOptions",
            "orders",
            "serviceable.user"
            )->where('status', 'Published')
            ->paginate(10);
            $minPrice = Service::min('basic_tier_price');
            $maxPrice = Service::max('pro_tier_price');
            if ($request->expectsJson()) {
                return response()->json($services);
            }

        $saved = [];
        if (Auth::check()) {
            $saved = $request->user()->savedServices();
        }

        return Inertia::render("Services/Index", [
            "categories" => $categories,
            "services" => $services,
            "skills" => $skills,
            "minPrice" => $minPrice,
            "maxPrice" => $maxPrice,
            "saved" => $saved,
        ]);
    }

    public function store(Request $request)
    {
        try {
            $transaction = DB::transaction(function () use ($request) {
                $attrs = $this->validateServiceRequest($request, false);
                $attrs["serviceable_id"] = $request->engineer
                    ? Auth::user()->engineer->id
                    : Auth::user()->firm->id;
                $attrs['slug']=Str::uuid()->toString();
                $attrs["serviceable_type"] = $request->engineer
                    ? "App\Models\Engineer"
                    : "App\Models\Firm";
                $service = Service::create($attrs);
                $service->categories()->attach($request->specialities);
                $service->skills()->attach($request->skills);
                $service->addLocation($request->location);
                if($request->file("files") != null &&
                    count($request->file("files")) > 0){
                    foreach ($request->file("files") as $item) {
                        ServiceImage::create([
                            "service_id" => $service->id,
                            "url" => FileUploader::store(
                                "serviceImages/",
                                $item
                            ),
                        ]);
                    }
                }

                if ($request->tier_options!=null && count($request->tier_options) > 0) {
                    foreach ($request->tier_options as $item) {
                        ServiceTierOption::create([
                            "title" => $item["title"],
                            "basic_enabled" => $item["basic_enabled"],
                            "standard_enabled" => $item["standard_enabled"],
                            "pro_enabled" => $item["pro_enabled"],
                            "service_id" => $service->id,
                        ]);
                    }
                }
                $service->searchable();
            });

            return is_null($transaction)
                ? back(303)->with(["success" => "success"])
                : $transaction;
        } catch (Exception $exception) {
            return redirect()->back()->withErrors(["error" => $exception->getMessage()])->with(["error" => $exception->getMessage()]);
        }
    }

    public function togglePause($slug)
    {
        $service = Service::where('slug',$slug)->firstOrFail();
        $service->togglePauseStatus();
        return back(303)->with(["success" => "success"]);
    }

    public function save($slug){
        $service = Service::where('slug',$slug)->firstOrFail();
        Auth::user()?->toggleLike($service);
        return back(303)->with(["success" => "success"]);
    }
    public function rate(Request $request, $slug){
        $service = Service::withTrashed()->where('slug',$slug)->firstOrFail();
        $service->addRate($request);
        return back(303)->with(['success', 'success']);
    }
    public function draft(Request $request)
    {
        try {
            $transaction = DB::transaction(function () use ($request) {
                $service = Service::saveDraft($request);
            });
            return is_null($transaction)
                ? back(303)->with(["success" => "success"])
                : $transaction;
        } catch (Exception $exception) {
            return redirect()->back()->withErrors(["error" => $exception->getMessage()])->with(["error" => $exception->getMessage()]);
        }
    }

    public function validateServiceRequest(Request $request, bool $update)
    {
        $request->validate([
            "tier_options" => ["array"],
            "files" =>"nullable|array",
            "files.*" => $update? "nullable" : UploadedFiles::getRules($update),
            "skills" => [$update ? "nullable" : "required", "array"],
            "skills.*" => $update
                ? "nullable"
                : ["integer", Rule::exists("skills", "id")],
            "location.long" => $update ? "nullable" : "required",
            "location.lat" => $update ? "nullable" : "required",
            "location.address" => $update ? "nullable" : "required",
            "specialities" => ["array", $update ? "nullable" : "required"],
            "specialities.*" => $update
                ? "nullable"
                : [Rule::exists("categories", "id")],
        ]);
        return $request->validate([
            "title" => [$update ? "nullable" : "required"],
            "description" => $update ? "nullable" : "required",
            "three_tiers" => $update ? "nullable" : "bool|required",
            "basic_tier_price" => $update ? "nullable" : "required|numeric",
            "standard_tier_price" => $update
                ? "nullable"
                : [Rule::excludeIf($request->three_tiers != true), "numeric"],
            "pro_tier_price" => $update
                ? "nullable"
                : [Rule::excludeIf($request->three_tiers != true), "numeric"],
            "basic_tier_days" => $update ? "nullable" : "numeric|required",
            "standard_tier_days" => $update
                ? "nullable"
                : [Rule::excludeIf($request->three_tiers != true), "numeric"],
            "pro_tier_days" => $update
                ? "nullable"
                : [Rule::excludeIf($request->three_tiers != true), "numeric"],
            "category_id" => $update
                ? "nullable"
                : [Rule::exists("categories", "id")],
            // 'engineer_id' => [Rule::excludeIf($request->has('firm_id')), Rule::exists('engineers', 'id')],
            // 'firm_id' => [Rule::excludeIf($request->has('engineer_id')), Rule::exists('firms', 'id')],
        ]);
    }

    /**
     * Show the form for creating a new resource.
     *
     * @return Response
     */
    public function create()
    {
        //
    }

    /**
     * Display the specified resource.
     *
     * @param Service $service
     * @return Response
     */
    public function show($slug)
    {
        $service = Service::where('slug',$slug)->firstOrFail();
        $service->load([
            "images",
            "skills",
            "location",
            "tierOptions",
            "orders",
            "serviceable" => ['user', 'location'],
            ]);
        foreach ($service->categories as $cat){
            $categoriesIds[]=$cat->id;
        }
        foreach ($service->skills as $skill){
            $skilIds[]=$skill->id;
        }


        $relatedServices = Service::with(
            "images",
            "skills",
            "location",
            "tierOptions",
            "orders",
            "serviceable.user"
        )
            ->where("id", "!=", $service->id)
            ->where("category_id", $service->category_id)
            ->orWhereHas('categories', function ($query) use ($categoriesIds) {
                return $query->whereIn('categories.id', $categoriesIds);
            })->
            orWhereHas('skills', function ($query) use ($skilIds) {
                return $query->whereIn('skills.id', $skilIds);
            })
            ->where("status", "Published")
            ->where("deleted_at", null)

            ->limit(2)
            ->get();

        return Inertia::render("Services/Single/Index", [
            "service" => $service,
            "relatedServices" => $relatedServices,
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     *
     * @param Service $service
     * @return Response
     */
    public function edit(Service $service)
    {
        //
    }

    public function update(Request $request, $slug)
    {
        $service = Service::where('slug',$slug)->first() ?? Service::getAllDrafts()->where('slug',$slug)->firstOrFail();
        try {
            $transaction = DB::transaction(function () use (
                $request,
                $service,

            ) {
                if ($service->draft!=null){
                    $attrs = $this->validateServiceRequest($request, false);
                    $attrs["serviceable_id"] = $request->engineer
                        ? Auth::user()->engineer->id
                        : Auth::user()->firm->id;
                    $attrs['slug']=$service->slug;
                    $attrs["serviceable_type"] = $request->engineer
                        ? "App\Models\Engineer"
                        : "App\Models\Firm";
                    $new = Service::create($attrs);
                    $service->delete();
                    $service->draft->delete();
                    $service=$new;
                }else{
                    $service->update($this->validateServiceRequest($request, true));
                }

                if($service->images!=null){
                    foreach ($service->images()->get() as $item) {
                        if (
                            !in_array(
                                $item->id,
                                array_column($request->file("files")??[], "id")
                            )
                        ) {
                            $item->delete();
                        }
                    }
                }

                if (
                    $request->file("files") != null &&
                    count($request->file("files")) > 0
                ) {
                    foreach ($request->file("files") as $item) {
                        ServiceImage::create([
                            "service_id" => $service->id,
                            "url" => FileUploader::store(
                                "serviceImages/",
                                $item
                            ),
                        ]);
                    }
                }
                if ($request->tier_options!=null && count($request->tier_options) > 0) {

                    foreach ($request->tier_options as $item) {
                        ServiceTierOption::create([
                            "title" => $item["title"],
                            "basic_enabled" => $item["basic_enabled"],
                            "standard_enabled" => $item["standard_enabled"],
                            "pro_enabled" => $item["pro_enabled"],
                            "service_id" => $service->id,
                        ]);
                    }
                }
                if($request->specialities!=null){
                    $service->categories()->sync($request->specialities);
                }
                if($request->skills!=null){
                    $service->skills()->sync($request->skills);
                }
                if($request->location!=null){
                    $service->addLocation($request->location);
                }
                $service->searchable();
                $service->save();
            });
            return is_null($transaction)
                ? back(303)->with(["success" => "success"])
                : $transaction;
        } catch (Exception $exception) {
            dd($exception);
            return redirect()->back()->withErrors(["error" => $exception->getMessage()])->with(["error" => $exception->getMessage()]);
        }
    }

    public function destroy($slug)
    {
        $service = Service::where('slug',$slug)->first()?? Service::getAllDrafts()->where('slug',$slug)->firstOrFail();
        $route =
            $service->serviceable_type == "App\Models\Engineer"
                ? "engineer.services.index"
                : "firm.services.index";

                if($service->draft!=null){
                    $service->draft->delete();
                }
        $service->delete();
        return redirect()
            ->route($route)
            ->with(["success" => "success"]);
    }

    public function acceptOrder(ServiceOrder $order)
    {
        $order->workerAccept();
        return back(303)->with(["success" => "success"]);
    }
    public function declineOrder(ServiceOrder $order)
    {
        $order->decline();
        return back(303)->with(["success" => "success"]);
    }
}
