<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Http\Requests\Report\ReportRequest;
use App\Http\Resources\ReportResource;
use App\Models\Report;
use App\Support\ApiResponse;
use App\Models\ReportConsumable;
use App\Models\ReportInvoiceItem;
use App\Models\ReportItem;
use Exception;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Gate;

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

        $query = Report::query()
            ->with(['project', 'producer', 'user', 'items.product', 'consumables', 'invoiceItems']);

        $user = $request->user();
        if ($user && ! $user->hasRole('admin')) {
            $query->where(function ($scope) use ($user): void {
                $scope->where('user_id', $user->id)
                    ->orWhere('created_by', $user->id)
                    ->orWhereHas('project', function ($projectQuery) use ($user): void {
                        $projectQuery->where('user_id', $user->id)
                            ->orWhere('created_by', $user->id)
                            ->orWhereHas('producer', fn ($producerQuery) => $producerQuery->where('user_id', $user->id));
                    });
            });
        }

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

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

        if ($request->filled('workflow_status')) {
            $query->where('workflow_status', $request->string('workflow_status'));
        }

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

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

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

        try {
            DB::beginTransaction();

            $data = $request->validated();
            $data['created_by'] = Auth::id();
            $data['user_id'] = $data['user_id'] ?? Auth::id();
            $data['workflow_status'] = $data['workflow_status'] ?? Report::WORKFLOW_PENDING;
            $data['report_at'] = $data['report_at'] ?? $data['date'];

            if ((int) $data['type'] === Report::TYPE_HEALTH) {
                $data['status'] = $data['status'] ?? 'draft';
            }

            $items = $data['items'] ?? null;
            $consumables = $data['consumables'] ?? null;
            $invoiceItems = $data['invoice_items'] ?? null;
            unset($data['items'], $data['consumables'], $data['invoice_items']);

            $report = Report::create($data);
            $this->syncNestedItems($report, $items, $consumables, $invoiceItems);

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

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

        return new ReportResource($report->load(['items.product', 'consumables', 'invoiceItems', 'project', 'producer']));
    }

    public function show(Report $report)
    {
        Gate::authorize('view', $report);

        return new ReportResource(
            $report->load([
                'items.product',
                'consumables',
                'invoiceItems',
                'rationIngredients',
                'feedingMeals',
                'rationWeekly',
                'project',
                'producer',
                'user',
                'product',
            ])
        );
    }

    public function update(ReportRequest $request, Report $report)
    {
        Gate::authorize('update', $report);

        try {
            DB::beginTransaction();

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

            $items = $data['items'] ?? null;
            $consumables = $data['consumables'] ?? null;
            $invoiceItems = $data['invoice_items'] ?? null;
            unset($data['items'], $data['consumables'], $data['invoice_items']);

            $report->update($data);
            $this->syncNestedItems($report, $items, $consumables, $invoiceItems);

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

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

        return new ReportResource($report->fresh()->load(['items.product', 'consumables', 'invoiceItems', 'project', 'producer']));
    }

    public function destroy(Report $report)
    {
        Gate::authorize('delete', $report);
        try {
            DB::beginTransaction();
            $report->delete();
            DB::commit();
        } catch (Exception $exception) {
            DB::rollBack();

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

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

    private function syncNestedItems(Report $report, ?array $items, ?array $consumables, ?array $invoiceItems): void
    {
        if ($items !== null) {
            $report->items()->delete();
            foreach ($items as $index => $item) {
                ReportItem::create([
                    'report_id' => $report->id,
                    'product_id' => $item['product_id'] ?? null,
                    'group_name' => $item['group_name'] ?? null,
                    'min_value' => $item['min_value'] ?? null,
                    'max_value' => $item['max_value'] ?? null,
                    'value' => $item['value'] ?? null,
                    'avg_value' => $item['avg_value'] ?? (
                        isset($item['min_value'], $item['max_value'])
                            ? ((float) $item['min_value'] + (float) $item['max_value']) / 2
                            : ($item['value'] ?? null)
                    ),
                    'unit' => $item['unit'] ?? null,
                    'action_note' => $item['action_note'] ?? null,
                    'sort_order' => $index,
                ]);
            }
        }

        if ($consumables !== null) {
            $report->consumables()->delete();
            foreach ($consumables as $index => $consumable) {
                ReportConsumable::create([
                    'report_id' => $report->id,
                    'name' => $consumable['name'],
                    'unit' => $consumable['unit'] ?? null,
                    'quantity' => $consumable['quantity'] ?? 0,
                    'unit_price' => $consumable['unit_price'] ?? null,
                    'sort_order' => $index,
                ]);
            }
        }

        if ($invoiceItems !== null) {
            $report->invoiceItems()->delete();
            foreach ($invoiceItems as $index => $invoiceItem) {
                ReportInvoiceItem::create([
                    'report_id' => $report->id,
                    'title' => $invoiceItem['title'],
                    'amount' => $invoiceItem['amount'] ?? 0,
                    'sort_order' => $index,
                ]);
            }
        }
    }
}
