<?php

declare(strict_types=1);

namespace App\Http\Controllers\Report;

use App\Http\Controllers\Concerns\AuthorizesProjectAccess;
use App\Http\Controllers\Controller;
use App\Http\Requests\Health\IndexHealthTreatmentRequest;
use App\Http\Requests\Health\StoreHealthTreatmentUpdateRequest;
use App\Http\Resources\HealthTreatmentResource;
use App\Http\Resources\HealthTreatmentUpdateResource;
use App\Models\HealthTreatment;
use App\Models\HealthTreatmentConsumable;
use App\Models\HealthTreatmentInvoiceItem;
use App\Models\HealthTreatmentUpdate;
use App\Models\Report;
use App\Support\ApiResponse;
use Exception;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class HealthTreatmentController extends Controller
{
    use AuthorizesProjectAccess;

    public function index(IndexHealthTreatmentRequest $request)
    {
        $user = $request->user();

        $query = HealthTreatment::query()
            ->with([
                'project:id,name,code,producer_id',
                'product:id,name,code,breed_id',
                'product.breed:id,name',
                'producer.user:id,name,mobile',
                'updates' => fn ($q) => $q->latest('report_at')->limit(1),
            ])
            ->latest('started_at')
            ->latest('id');

        $this->restrictVisibility($query, $user);

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

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

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

        if ($request->filled('product')) {
            $term = $request->string('product');
            $query->where(function (Builder $q) use ($term): void {
                $q->where('product_name', 'like', "%{$term}%")
                    ->orWhere('product_code', 'like', "%{$term}%")
                    ->orWhere('breed_name', 'like', "%{$term}%")
                    ->orWhereHas('product', fn (Builder $pq) => $pq->where('name', 'like', "%{$term}%")->orWhere('code', 'like', "%{$term}%"));
            });
        }

        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 $q) use ($term): void {
                $q->where('brand_name', 'like', "%{$term}%")
                    ->orWhereHas('user', fn (Builder $uq) => $uq->where('name', 'like', "%{$term}%"));
            });
        }

        if ($request->filled('status')) {
            $query->where('status', $request->string('status'));
        } elseif (! $request->boolean('include_ended')) {
            $query->active();
        }

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

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

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

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

    public function show(Request $request, HealthTreatment $healthTreatment)
    {
        $this->authorizeProjectAccess($healthTreatment->project);

        $healthTreatment->load([
            'project',
            'product.breed',
            'producer.user',
            'initialReport.consumables',
            'initialReport.invoiceItems',
            'updates.consumables',
            'updates.invoiceItems',
            'updates.createdBy',
        ]);

        return ApiResponse::success(new HealthTreatmentResource($healthTreatment));
    }

    public function storeUpdate(StoreHealthTreatmentUpdateRequest $request, HealthTreatment $healthTreatment)
    {
        $user = $request->user();
        $this->authorizeProjectAccess($healthTreatment->project);
        $this->assertCanManage($user, $healthTreatment);

        if (! $healthTreatment->isActive()) {
            return ApiResponse::badRequest('این محصول دیگر تحت درمان/نظارت فعال نیست.');
        }

        $data = $request->validated();

        try {
            DB::beginTransaction();

            /** @var HealthTreatmentUpdate $update */
            $update = $healthTreatment->updates()->create([
                'report_at' => $data['report_at'] ?? now(),
                'progress_percent' => $data['progress_percent'] ?? 0,
                'notes' => $data['notes'] ?? null,
                'expert_opinion' => $data['expert_opinion'] ?? null,
                'written_report' => $data['written_report'] ?? null,
                'total_cost' => $data['total_cost'] ?? null,
                'invoice_image' => $data['invoice_image'] ?? null,
                'attachments' => $data['attachments'] ?? null,
                'documents' => $data['documents'] ?? null,
                'created_by' => $user->id,
            ]);

            foreach ($data['consumables'] ?? [] as $index => $row) {
                HealthTreatmentConsumable::create([
                    'health_treatment_update_id' => $update->id,
                    'name' => $row['name'],
                    'unit' => $row['unit'] ?? null,
                    'quantity' => $row['quantity'] ?? 0,
                    'unit_price' => $row['unit_price'] ?? null,
                    'sort_order' => $index,
                ]);
            }

            foreach ($data['invoice_items'] ?? [] as $index => $row) {
                HealthTreatmentInvoiceItem::create([
                    'health_treatment_update_id' => $update->id,
                    'title' => $row['title'],
                    'amount' => $row['amount'] ?? 0,
                    'sort_order' => $index,
                ]);
            }

            $progress = (int) ($data['progress_percent'] ?? 0);
            $healthTreatment->update([
                'progress_percent' => $progress,
                'status' => $progress >= 100
                    ? HealthTreatment::STATUS_COMPLETED
                    : HealthTreatment::STATUS_UNDER_TREATMENT,
                'ended_at' => $progress >= 100 ? ($data['report_at'] ?? now()) : null,
                'attachments' => $data['attachments'] ?? $healthTreatment->attachments,
                'updated_by' => $user->id,
            ]);

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

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

        return ApiResponse::created(
            new HealthTreatmentUpdateResource($update->fresh(['consumables', 'invoiceItems', 'createdBy'])),
            'پیشرفت درمان ثبت شد.'
        );
    }

    public function history(Request $request, HealthTreatment $healthTreatment)
    {
        $this->authorizeProjectAccess($healthTreatment->project);

        $healthTreatment->load([
            'updates.consumables',
            'updates.invoiceItems',
            'updates.createdBy',
            'initialReport.consumables',
            'producer.user',
            'product',
        ]);

        $vaccinationReports = Report::query()
            ->where('type', Report::TYPE_HEALTH)
            ->where('project_id', $healthTreatment->project_id)
            ->where('report_type', Report::HEALTH_TYPE_VACCINATION)
            ->where(function (Builder $q) use ($healthTreatment): void {
                $q->where('product_id', $healthTreatment->product_id)
                    ->orWhereHas('items', fn (Builder $iq) => $iq->where('product_id', $healthTreatment->product_id));
            })
            ->where('workflow_status', Report::WORKFLOW_APPROVED)
            ->with(['consumables', 'producer'])
            ->orderByDesc('report_at')
            ->get()
            ->map(fn (Report $r) => [
                'id' => $r->id,
                'date' => optional($r->report_at ?? $r->date)?->toDateString(),
                'vaccine_name' => $r->disease_name,
                'service_provider' => $r->producer ? [
                    'id' => $r->producer->id,
                    'name' => $r->producer->brand_name,
                ] : null,
                'consumables' => $r->consumables,
                'period' => [
                    'from' => optional($r->report_at ?? $r->date)?->toDateString(),
                    'to' => optional($r->next_visit_at)?->toDateString(),
                ],
            ]);

        return ApiResponse::success([
            'treatment' => new HealthTreatmentResource($healthTreatment),
            'order_history' => HealthTreatmentUpdateResource::collection($healthTreatment->updates),
            'vaccinations' => $vaccinationReports,
        ]);
    }

    private function restrictVisibility(Builder $query, $user): void
    {
        if ($user->hasRole('admin')) {
            return;
        }

        $query->whereHas('project', function (Builder $q) use ($user): void {
            $q->where('user_id', $user->id)
                ->orWhere('created_by', $user->id)
                ->orWhereHas('producer', fn (Builder $p) => $p->where('user_id', $user->id));
        });
    }

    private function assertCanManage($user, HealthTreatment $treatment): void
    {
        if ($user->hasRole('admin')) {
            return;
        }

        if ($treatment->producer && $treatment->producer->user_id === $user->id) {
            return;
        }

        if ($treatment->project?->producer && $treatment->project->producer->user_id === $user->id) {
            return;
        }

        abort(403, 'دسترسی مجاز نیست.');
    }
}
