<?php

namespace App\Http\Controllers;

use App\DealershipRepository;
use App\Facades\Settings;
use App\Http\Requests\CopyDealershipRequest;
use App\Http\Requests\StoreDealershipRequest;
use App\Http\Requests\UpdateDealershipRequest;
use App\Http\Resources\DealershipListResource;
use App\Http\Resources\DealershipViewResource;
use App\SavesSeoData;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB;
use App\Traits\EnsuresVehicleAttribute;
use Illuminate\Support\Facades\Log;
use Mtc\ContentManager\Facades\Media;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\DealershipDepartment;
use Illuminate\Http\Request;

class DealershipController extends Controller
{
    use SavesSeoData;
    use EnsuresVehicleAttribute;

    public function __construct()
    {
        $this->middleware([
            'permission:edit-dealerships',
        ]);
    }

    /**
     * Display a listing of dealerships
     *
     * @return DealershipListResource
     */
    public function index(Request $request): DealershipListResource
    {
        $perPage = min((int)$request->input('per_page', 15), 200);

        return new DealershipListResource(Dealership::query()
            ->with([
                'mediaUses.media',
                'departments',
            ])
            ->withVehicleCount()
            ->search($request->input('search_term'))
            ->setSortBy($request->input('sort_by'))
            ->paginate($perPage));
    }

    /**
     * Store a newly created dealership
     *
     * @param StoreDealershipRequest $request
     * @return DealershipViewResource
     */
    public function store(StoreDealershipRequest $request): DealershipViewResource
    {
        $dealership = Dealership::query()->create([
            'name' => $request->input('name')
        ]);

        $this->upsertDepartments($dealership, $request->input('departments', []));

        $dealership->refresh();
        return new DealershipViewResource($dealership);
    }

    /**
     * Display the specified dealership.
     *
     * @param Dealership $dealership
     * @return DealershipViewResource
     */
    public function show(Dealership $dealership): DealershipViewResource
    {
        return new DealershipViewResource($dealership);
    }

    /**
     * Update the specified dealership.
     *
     * @param UpdateDealershipRequest $request
     * @param Dealership $dealership
     * @return DealershipViewResource
     */
    public function update(
        UpdateDealershipRequest $request,
        Dealership $dealership,
        DealershipRepository $repository
    ): DealershipViewResource {
        $coordinates = collect($request->input('coordinates'))->only(['lat', 'lng'])->implode(',');
        $dealership->fill([
            'name' => $request->input('name'),
            'email' => $request->input('email'),
            'active' => $request->input('active', 1),
            'contact_no' => $request->input('contact_no'),
            'address1' => $request->input('address1'),
            'address2' => $request->input('address2'),
            'city' => $request->input('city'),
            'county' => $request->input('county'),
            'postcode' => $request->input('postcode'),
            'country' => $request->input('country'),
            'open_times' => $request->input('open_times'),
            'alt_open_times' => Settings::get('dealership-second-open-times')
                ? $request->input('alt_open_times')
                : null,
            'second_alt_open_times' => Settings::get('dealership-third-open-times')
                ? $request->input('second_alt_open_times')
                : null,
            'data' => $request->input('data'),
            'coordinates' => $coordinates,
            'timezone' => Settings::get('app-dealership-timezone') ? $request->input('timezone') : null,
            'contact_form_id' => $request->input('contact_form_id'),
            'notes' => $request->input('notes'),
            'location_stock' => $request->input('location_stock'),
            'external_showroom_url' => $request->input('external_showroom_url'),
            'template_id' => $request->input('template_id'),
        ]);
        if (Settings::get('dealerships-multiple-franchises')) {
            $dealership->franchises()->sync($request->input('franchise_ids'));
        } else {
            $dealership['franchise_id'] = $request->input('franchise_id');
        }
        $dealership->slug = $request->input('seo.slug') ?? $dealership->slug;
        if ($request->filled('seo')) {
            $this->saveSeo($dealership, $request->input('seo', []));
        }
        $dealership->save();
        $dealership->allocateHolidays($request->input('holidays', []));
        Media::setUsesForModel($request->input('media', []), $dealership, ['primary' => true], true);

        $repository->saveContent($dealership, $request);
        $this->upsertDepartments($dealership, $request->input('departments', []));

        collect($request->input('extra', []))
            ->filter(fn($attribute) => isset($attribute['value']) && empty($attribute['readonly']))
            ->each(fn($attribute) => $this->saveAttributeValue($dealership, $attribute));

        return new DealershipViewResource($dealership);
    }

    /**
     * Remove the specified dealership from storage.
     *
     * @param Dealership $dealership
     * @return bool
     */
    public function destroy(Dealership $dealership): bool
    {
        $dealership->departments()->delete();
        $dealership->allHolidays()->delete();
        return $dealership->delete();
    }

    /**
     * Save the order of dealerships.
     *
     * @param Request $request
     * @return Response|JsonResponse
     */
    public function saveOrder(Request $request): Response|JsonResponse
    {
        $ids = collect($request->input())->pluck('id');

        try {
            DB::transaction(static function () use ($ids) {
                $ids->each(fn ($id, $index) => Dealership::query()
                    ->where('id', $id)
                    ->update([
                        'order' => $index + 1,
                    ]));
            });

            return response('ok');
        } catch (\Throwable $e) {
            Log::error('Failed to save dealership order', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
                'tenant' => tenant('id'),
            ]);

            return response()->json([
                'status' => 'error',
                'message' => 'Failed to save the new order. Please try again.',
            ], 500);
        }
    }

    public function copy(CopyDealershipRequest $request, Dealership $dealership): DealershipViewResource
    {
        $copy = Dealership::query()
            ->create([
                'name' => $dealership->name,
                'email' => $dealership->email,
                'contact_no' => $dealership->contact_no,
                'address1' => $dealership->address1,
                'address2' => $dealership->address2,
                'city' => $dealership->city,
                'county' => $dealership->county,
                'postcode' => $dealership->postcode,
                'country' => $dealership->country,
                'open_times' => $dealership->open_times,
                'data' => $dealership->data,
                'coordinates' => $dealership->coordinates,
                'contact_form_id' => $dealership->contact_form_id,
                'template_id' => $dealership->template_id,
            ]);
        Media::setUsesForModel($dealership->mediaUses()->pluck('media_id')->toArray(), $copy);
        return new DealershipViewResource($copy);
    }

    /**
     * Sync offer content with template
     *
     * @param int $dealershipId
     * @param DealershipRepository $repository
     * @return DealershipViewResource|array
     */
    public function syncWithTemplate(int $dealershipId, DealershipRepository $repository): DealershipViewResource|array
    {
        try {
            $repository->syncContentWithTemplate($dealershipId);
            $dealership = Dealership::query()->find($dealershipId);
        } catch (\Exception $exception) {
            Log::error('Failed to sync dealership structure ', [
                'page_id' => $dealershipId,
                'error' => $exception->getMessage(),
                'tenant' => tenant('id'),
            ]);
            return [
                'success' => false,
                'error' => $exception->getMessage(),
            ];
        }

        return new DealershipViewResource($dealership);
    }

    private function upsertDepartments(Dealership $dealership, array $departments)
    {
        $dealership->departments()
            ->whereNotIn('id', collect($departments)->pluck('id'))
            ->delete();

        collect($departments)->each(function ($department) use ($dealership) {
            DealershipDepartment::query()->updateOrCreate(
                [
                    'id' => $department['id'],
                    'dealership_id' => $dealership->id,
                ],
                $department,
            );
        });
    }
}
