<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\ProjectRequest\IndexProjectRequestRequest;
use App\Http\Requests\ProjectRequest\MessageProjectRequestRequest;
use App\Http\Requests\ProjectRequest\StoreProjectRequestSubmission;
use App\Http\Requests\ProjectRequest\UpdateProjectRequestStatusRequest;
use App\Http\Resources\ProjectRequestResource;
use App\Models\Project;
use App\Models\ProjectRequest;
use App\Notifications\SimpleDatabaseNotification;
use App\Support\ApiResponse;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class ProjectRequestController extends Controller
{
    public function index(IndexProjectRequestRequest $request)
    {
        Gate::authorize('viewAny', ProjectRequest::class);

        $query = ProjectRequest::query()
            ->with(['producer.user', 'createdBy', 'reviewedBy', 'project'])
            ->latest();

        $user = $request->user();

        if (! $user->hasRole('admin')) {
            $producerId = $user->producer?->id;
            $query->where(function (Builder $builder) use ($user, $producerId): void {
                $builder->where('created_by', $user->id);
                if ($producerId) {
                    $builder->orWhere('producer_id', $producerId);
                }
            });
        }

        if ($request->filled('status')) {
            $query->where('status', $request->input('status'));
        }

        if ($request->filled('producer')) {
            $term = $request->input('producer');
            $query->whereHas('producer', function (Builder $producerQuery) use ($term): void {
                $producerQuery->where('brand_name', 'like', "%{$term}%")
                    ->orWhereHas('user', function (Builder $userQuery) use ($term): void {
                        $userQuery->where('first_name', 'like', "%{$term}%")
                            ->orWhere('last_name', 'like', "%{$term}%");
                    });
            });
        }

        if ($request->filled('from')) {
            $query->whereDate('created_at', '>=', $request->date('from'));
        }

        if ($request->filled('to')) {
            $query->whereDate('created_at', '<=', $request->date('to'));
        }

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

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

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

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

        if (! $producer) {
            return ApiResponse::badRequest('پروفایل تولیدکننده یافت نشد.');
        }

        try {
            DB::beginTransaction();

            $projectRequest = ProjectRequest::create([
                'producer_id' => $producer->id,
                'title' => $request->input('title'),
                'payload' => $request->input('payload'),
                'status' => ProjectRequest::STATUS_WAITING,
                'created_by' => $request->user()->id,
            ]);

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

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

        return ApiResponse::created(
            new ProjectRequestResource($projectRequest->load(['producer.user', 'createdBy'])),
            'درخواست پروژه با موفقیت ثبت شد.'
        );
    }

    public function show(ProjectRequest $projectRequest)
    {
        Gate::authorize('view', $projectRequest);

        return new ProjectRequestResource(
            $projectRequest->load(['producer.user', 'createdBy', 'reviewedBy', 'project'])
        );
    }

    public function updateStatus(UpdateProjectRequestStatusRequest $request, ProjectRequest $projectRequest)
    {
        Gate::authorize('updateStatus', $projectRequest);

        $status = $request->input('status');
        $adminNote = $request->input('admin_note');

        if (in_array($status, [ProjectRequest::STATUS_REJECTED, ProjectRequest::STATUS_EDIT], true) && blank($adminNote)) {
            return ApiResponse::badRequest('ثبت توضیحات برای رد یا درخواست ویرایش الزامی است.');
        }

        try {
            DB::beginTransaction();

            $projectRequest->update([
                'status' => $status,
                'admin_note' => $adminNote,
                'reviewed_by' => $request->user()->id,
                'reviewed_at' => now(),
            ]);

            if ($status === ProjectRequest::STATUS_APPROVED && $request->boolean('create_project', true) && ! $projectRequest->project_id) {
                $payload = $projectRequest->payload ?? [];
                $project = Project::create([
                    'name' => $projectRequest->title,
                    'producer_id' => $projectRequest->producer_id,
                    'project_request_id' => $projectRequest->id,
                    'category_id' => $payload['category_id'] ?? null,
                    'breed_id' => $payload['breed_id'] ?? null,
                    'product_id' => $payload['product_id'] ?? null,
                    'quantity' => $payload['quantity'] ?? null,
                    'unit' => $payload['unit'] ?? null,
                    'unit_price' => $payload['unit_price'] ?? null,
                    'desc' => $payload['desc'] ?? null,
                    'estimated_profit' => $payload['estimated_profit'] ?? null,
                    'province_id' => $payload['province_id'] ?? null,
                    'county_id' => $payload['county_id'] ?? null,
                    'start_date' => $payload['start_date'] ?? null,
                    'end_date' => $payload['end_date'] ?? null,
                    'status' => Project::STATUS_PENDING,
                    'created_by' => $request->user()->id,
                    'updated_by' => $request->user()->id,
                ]);

                $projectRequest->update(['project_id' => $project->id]);
            }

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

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

        $producerUser = $projectRequest->producer?->user;
        if ($producerUser) {
            $label = ProjectRequest::statusOptions()[$status] ?? $status;
            $producerUser->notify(new SimpleDatabaseNotification(
                'تغییر وضعیت درخواست پروژه',
                "وضعیت درخواست «{$projectRequest->title}» به «{$label}» تغییر کرد." . ($adminNote ? " توضیح: {$adminNote}" : ''),
                [
                    'type' => 'project_request_status',
                    'project_request_id' => $projectRequest->id,
                    'status' => $status,
                ]
            ));
        }

        return ApiResponse::success(
            new ProjectRequestResource($projectRequest->fresh()->load(['producer.user', 'createdBy', 'reviewedBy', 'project'])),
            'وضعیت درخواست به‌روزرسانی شد.'
        );
    }

    public function message(MessageProjectRequestRequest $request, ProjectRequest $projectRequest)
    {
        Gate::authorize('message', $projectRequest);

        $producerUser = $projectRequest->producer?->user;
        if (! $producerUser) {
            return ApiResponse::notFound('کاربر تولیدکننده یافت نشد.');
        }

        $title = $request->input('title') ?: 'پیام ادمین درباره درخواست پروژه';
        $producerUser->notify(new SimpleDatabaseNotification(
            $title,
            $request->input('body'),
            [
                'type' => 'project_request_message',
                'project_request_id' => $projectRequest->id,
            ]
        ));

        return ApiResponse::success(message: 'پیام برای تولیدکننده ارسال شد.');
    }
}
