<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Controllers\Concerns\AuthorizesProjectAccess;
use App\Http\Requests\Project\ProjectListRequest;
use App\Http\Requests\Project\StoreProjectRequest;
use App\Http\Requests\Project\UpdateProjectRequest;
use App\Http\Requests\Project\UpdateSaleRegistrationRequest;
use App\Http\Resources\ProjectSummaryResource;
use App\Models\Invoice;
use App\Models\Project;
use App\Services\ProjectProfitChartService;
use App\Support\ApiResponse;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

class ProjectController extends Controller
{
    use AuthorizesProjectAccess;

    public function __construct(
        private readonly ProjectProfitChartService $profitChartService
    ) {}

    public function index(ProjectListRequest $request)
    {
        Gate::authorize('viewAny', Project::class);

        $query = $this->accessibleProjectsQuery()
            ->withApiRelations()
            ->with($this->profitChartEagerLoads());

        $this->applyFilters($query, $request);

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

        $projects = $request->boolean('noPaginate')
            ? $query->get()
            : $query->paginate($perPage);

        $this->profitChartService->attachChartPoints(
            $projects instanceof \Illuminate\Pagination\AbstractPaginator
                ? $projects->getCollection()
                : $projects
        );

        return ProjectSummaryResource::collection($projects);
    }

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

        try {
            DB::beginTransaction();

            $data = $request->safe()->except(['is_draft']);
            $data['created_by'] = Auth::id();
            $data['updated_by'] = Auth::id();
            $data['status'] = $request->boolean('is_draft')
                ? Project::STATUS_PENDING
                : Project::STATUS_UNSIGNED;
            $data['sale_registration_enabled'] = $request->boolean('sale_registration_enabled', true);

            $project = Project::create($data);

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

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

        return ApiResponse::created(
            new ProjectSummaryResource($project->loadApiRelations()),
            'پروژه با موفقیت ثبت شد.'
        );
    }

    public function show(Project $project)
    {
        Gate::authorize('view', $project);

        $project->loadApiRelations()->load([
            'contractSignatures',
            'completion',
            ...$this->profitChartEagerLoads(),
        ]);

        $this->profitChartService->attachChartPoints([$project]);

        return new ProjectSummaryResource($project);
    }

    public function update(UpdateProjectRequest $request, Project $project)
    {
        Gate::authorize('update', $project);

        try {
            DB::beginTransaction();

            $data = $request->safe()->except(['is_draft']);
            $data['updated_by'] = Auth::id();

            if ($request->has('is_draft') && ! $request->boolean('is_draft') && $project->status === Project::STATUS_PENDING) {
                $data['status'] = Project::STATUS_UNSIGNED;
            }

            $project->update($data);

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

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

        return ApiResponse::success(
            new ProjectSummaryResource($project->fresh()->loadApiRelations()),
            'پروژه با موفقیت ویرایش شد.'
        );
    }

    public function updateSaleRegistration(UpdateSaleRegistrationRequest $request, Project $project)
    {
        Gate::authorize('update', $project);

        $project->update([
            'sale_registration_enabled' => $request->boolean('sale_registration_enabled'),
            'sale_deactivation_at' => $request->input('sale_deactivation_at'),
            'updated_by' => Auth::id(),
        ]);

        return ApiResponse::success(
            new ProjectSummaryResource($project->fresh()->loadApiRelations()),
            'وضعیت ثبت درخواست فروش به‌روزرسانی شد.'
        );
    }

    public function destroy(Project $project)
    {
        Gate::authorize('delete', $project);

        try {
            DB::beginTransaction();
            $project->delete();
            DB::commit();
        } catch (Exception $exception) {
            DB::rollBack();

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

        return ApiResponse::success(message: 'با موفقیت حذف شد');
    }

    /**
     * @return array<string, callable>
     */
    private function profitChartEagerLoads(): array
    {
        return [
            'invoices' => fn ($query) => $query
                ->whereIn('status', [Invoice::STATUS_PAID, Invoice::STATUS_APPROVED])
                ->select(['id', 'project_id', 'type', 'total', 'status', 'issued_at', 'created_at']),
        ];
    }

    private function applyFilters(Builder $query, ProjectListRequest $request): void
    {
        if ($request->filled('status')) {
            $query->where('status', $request->string('status'));
        }

        if ($request->filled('q')) {
            $search = $request->string('q');
            $query->where(function (Builder $scope) use ($search): void {
                $scope->where('name', 'like', "%{$search}%")
                    ->orWhere('code', 'like', "%{$search}%");
            });
        }

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

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

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

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

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

        if ($request->filled('producer')) {
            $term = $request->string('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}%")
                            ->orWhere('national_code', 'like', "%{$term}%")
                            ->orWhere('cellphone', 'like', "%{$term}%");
                    });
            });
        }

        if ($request->has('sale_registration_enabled')) {
            $query->where('sale_registration_enabled', $request->boolean('sale_registration_enabled'));
        }
    }
}
