<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\ServiceRequest\DeclineServiceRequestRequest;
use App\Http\Requests\ServiceRequest\StoreServiceRequestRequest;
use App\Http\Resources\ServiceRequestResource;
use App\Models\ConsultationRequest;
use App\Models\Expert;
use App\Models\Producer;
use App\Support\ApiResponse;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class ServiceRequestController extends Controller
{
    public function index(Request $request)
    {
        Gate::authorize('viewAny', ConsultationRequest::class);

        $user = $request->user();
        $scope = $request->string('scope')->toString();

        if ($scope === '') {
            if ($user->producer) {
                $scope = 'producer';
            } elseif ($user->expert) {
                $scope = 'expert';
            } elseif ($user->hasRole('admin')) {
                $scope = 'all';
            } else {
                $scope = 'producer';
            }
        }

        $query = ConsultationRequest::query()
            ->with(['producer.user', 'expert.user']);

        if ($scope === 'expert') {
            $expert = $user->expert;
            if (! $expert && ! $user->hasRole('admin')) {
                return ApiResponse::forbidden('پروفایل خدمات‌دهنده یافت نشد.');
            }

            if ($expert) {
                $query->where('expert_id', $expert->id)
                    ->where('status', ConsultationRequest::STATUS_APPROVED);
            }
        } elseif ($scope === 'producer') {
            $producer = $user->producer;
            if (! $producer && ! $user->hasRole('admin')) {
                return ApiResponse::forbidden('پروفایل تولیدکننده یافت نشد.');
            }

            if ($producer) {
                $query->where('producer_id', $producer->id);
            }
        } elseif ($scope !== 'all' || ! $user->hasRole('admin')) {
            return ApiResponse::badRequest('scope باید producer، expert یا all باشد.');
        }

        if ($request->filled('status')) {
            $this->applyApiStatusFilter($query, $request->string('status')->toString());
        }

        if ($request->filled('expert_id')) {
            $query->where('expert_id', $request->integer('expert_id'));
        }

        $perPage = min($request->integer('per_page', 15), 50);

        return ServiceRequestResource::collection(
            $request->boolean('noPaginate') ? $query->latest()->get() : $query->latest()->paginate($perPage)
        );
    }

    public function store(StoreServiceRequestRequest $request)
    {
        Gate::authorize('create', ConsultationRequest::class);

        $user = $request->user();
        $producer = $user->producer;

        if (! $producer && ! $user->hasRole('admin')) {
            return ApiResponse::badRequest('برای ثبت درخواست مشاوره باید پروفایل تولیدکننده داشته باشید.');
        }

        if ($user->hasRole('admin') && $request->filled('producer_id')) {
            $producer = Producer::query()->findOrFail($request->integer('producer_id'));
        }

        if (! $producer) {
            return ApiResponse::badRequest('تولیدکننده مشخص نیست.');
        }

        $expert = Expert::query()->findOrFail($request->integer('expert_id'));

        if (! in_array($expert->status, [Expert::STATUS_APPROVED, 'active'], true) && ! $user->hasRole('admin')) {
            return ApiResponse::badRequest('این خدمات‌دهنده در حال حاضر قابل انتخاب نیست.');
        }

        try {
            DB::beginTransaction();

            $serviceRequest = ConsultationRequest::create([
                'producer_id' => $producer->id,
                'expert_id' => $expert->id,
                'type' => $this->normalizeType($request->string('consultation_type')->toString()),
                'format' => $request->string('mode')->toString(),
                'priority' => $this->normalizePriority($request->string('priority')->toString()),
                'message' => $request->string('message')->toString(),
                'status' => ConsultationRequest::STATUS_PENDING,
                'production_address' => $request->input('production_address') ?? $producer->work_address,
                'producer_contact' => $request->input('producer_contact')
                    ?? $producer->work_phone
                    ?? $user->cellphone,
            ]);

            DB::commit();
        } catch (Exception $exception) {
            DB::rollBack();

            return ApiResponse::response(message: $exception->getMessage(), status: 419);
        }

        return ApiResponse::created(
            new ServiceRequestResource($serviceRequest->load(['producer.user', 'expert.user'])),
            'درخواست مشاوره ثبت شد و در انتظار بررسی ادمین است.'
        );
    }

    public function show(ConsultationRequest $serviceRequest)
    {
        Gate::authorize('view', $serviceRequest);

        $serviceRequest->load(['producer.user', 'expert.user']);

        return new ServiceRequestResource($serviceRequest);
    }

    public function accept(ConsultationRequest $serviceRequest)
    {
        Gate::authorize('accept', $serviceRequest);

        if ($serviceRequest->status !== ConsultationRequest::STATUS_APPROVED) {
            return ApiResponse::badRequest('فقط درخواست‌های تاییدشده توسط ادمین قابل پذیرش هستند.');
        }

        if ($serviceRequest->provider_can_visit !== null) {
            return ApiResponse::badRequest('وضعیت مراجعه قبلاً ثبت شده است.');
        }

        $serviceRequest->update([
            'provider_can_visit' => true,
        ]);

        return ApiResponse::success(
            new ServiceRequestResource($serviceRequest->fresh()->load(['producer.user', 'expert.user'])),
            'مراجعه پذیرفته شد.'
        );
    }

    public function decline(DeclineServiceRequestRequest $request, ConsultationRequest $serviceRequest)
    {
        Gate::authorize('decline', $serviceRequest);

        if ($serviceRequest->status !== ConsultationRequest::STATUS_APPROVED) {
            return ApiResponse::badRequest('فقط درخواست‌های تاییدشده توسط ادمین قابل رد هستند.');
        }

        if ($serviceRequest->provider_can_visit !== null) {
            return ApiResponse::badRequest('وضعیت مراجعه قبلاً ثبت شده است.');
        }

        $reason = $request->input('reason');
        $notes = $serviceRequest->admin_notes;
        if (is_string($reason) && $reason !== '') {
            $notes = trim(($notes ? $notes . "\n" : '') . 'رد خدمات‌دهنده: ' . $reason);
        }

        $serviceRequest->update([
            'provider_can_visit' => false,
            'admin_notes' => $notes,
        ]);

        return ApiResponse::success(
            new ServiceRequestResource($serviceRequest->fresh()->load(['producer.user', 'expert.user'])),
            'مراجعه رد شد.'
        );
    }

    private function normalizeType(string $type): string
    {
        return match ($type) {
            'herd_management', 'herd' => ConsultationRequest::TYPE_HERD,
            'feed' => ConsultationRequest::TYPE_FEED,
            default => ConsultationRequest::TYPE_OTHER,
        };
    }

    private function normalizePriority(string $priority): string
    {
        return match ($priority) {
            'medium', 'normal' => ConsultationRequest::PRIORITY_NORMAL,
            'high', 'urgent' => ConsultationRequest::PRIORITY_URGENT,
            'emergency' => ConsultationRequest::PRIORITY_EMERGENCY,
            'low' => ConsultationRequest::PRIORITY_LOW,
            default => ConsultationRequest::PRIORITY_NORMAL,
        };
    }

    private function applyApiStatusFilter($query, string $status): void
    {
        match ($status) {
            'pending' => $query->where('status', ConsultationRequest::STATUS_PENDING),
            'rejected' => $query->where('status', ConsultationRequest::STATUS_REJECTED),
            'closed' => $query->where('status', ConsultationRequest::STATUS_CLOSED),
            'pending_expert' => $query
                ->where('status', ConsultationRequest::STATUS_APPROVED)
                ->whereNull('provider_can_visit'),
            'accepted' => $query
                ->where('status', ConsultationRequest::STATUS_APPROVED)
                ->where('provider_can_visit', true),
            'declined' => $query
                ->where('status', ConsultationRequest::STATUS_APPROVED)
                ->where('provider_can_visit', false),
            'approved' => $query->where('status', ConsultationRequest::STATUS_APPROVED),
            default => $query->where('status', $status),
        };
    }
}
