<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Requests\WebFace\StoreOrderRequest;
use App\Http\Requests\WebFace\UpdateOrderStatusRequest;
use App\Jobs\SyncOrderToOmsJob;
use App\Models\OrderChannelCatalog;
use App\Models\OrderTypeCatalog;
use App\Models\OrderStatusCatalog;
use App\Models\OrderCarrierCatalog;
use App\Models\Order;
use App\Models\Province;
use App\Models\Canton;
use App\Models\District;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use App\Models\Store;
use Illuminate\Validation\ValidationException;

class WebFaceOrderController extends Controller
{
    public function store(StoreOrderRequest $request): JsonResponse
    {
        $payload = $request->validated();

        $orderReference = $payload['order_reference'];

        $existing = Order::query()->where('order_reference', $orderReference)->first();
        if ($existing) {
            SyncOrderToOmsJob::dispatch($existing->order_reference)->afterResponse();

            return response()->json([
                'message' => 'Order already exists (idempotent).',
                'order_reference' => $existing->order_reference,
                'id_order' => $existing->id_order,
            ], 200);
        }

        $order = DB::transaction(function () use ($payload): Order {
            $statusCode = $payload['status'];

            $channelId = OrderChannelCatalog::query()->where('code', $payload['channel'])->value('id_order_channel');
            $orderTypeId = OrderTypeCatalog::query()->where('code', $payload['order_type'])->value('id_order_type');
            $statusId = OrderStatusCatalog::query()->where('code', $payload['status'])->value('id_order_status');
            $carrierId = filled($payload['carrier'] ?? null)
                ? OrderCarrierCatalog::query()->where('code', $payload['carrier'])->value('id_order_carrier')
                : null;

            if (! $channelId) {
                throw ValidationException::withMessages(['channel' => 'Canal inválido.']);
            }
            if (! $orderTypeId) {
                throw ValidationException::withMessages(['order_type' => 'Tipo de orden inválido.']);
            }
            if (! $statusId) {
                throw ValidationException::withMessages(['status' => 'Estado inválido.']);
            }
            if (filled($payload['carrier'] ?? null) && ! $carrierId) {
                throw ValidationException::withMessages(['carrier' => 'Carrier inválido.']);
            }

            // Geo: resolve IDs desde textos
            $provinceId = Province::query()->where('name', $payload['province'])->value('id_province');
            if (! $provinceId) {
                throw ValidationException::withMessages(['province' => 'Provincia inválida.']);
            }

            $cantonId = Canton::query()
                ->where('province_id', $provinceId)
                ->where('name', $payload['canton'])
                ->value('id_canton');
            if (! $cantonId) {
                throw ValidationException::withMessages(['canton' => 'Cantón inválido.']);
            }

            $districtId = District::query()
                ->where('canton_id', $cantonId)
                ->where('name', $payload['district'])
                ->value('id_district');
            if (! $districtId) {
                throw ValidationException::withMessages(['district' => 'Distrito inválido.']);
            }

            $details = array_map(function (array $row): array {
                $qty = (int) ($row['product_quantity'] ?? 0);
                $priceTI = (float) ($row['product_priceTI'] ?? 0);
                $priceTE = (float) ($row['product_priceTE'] ?? 0);

                $row['total_priceTI'] = $qty * $priceTI;
                $row['total_priceTE'] = $qty * $priceTE;

                return $row;
            }, $payload['details']);
            unset($payload['details']);

            $payload['channel_id'] = $channelId;
            $payload['order_type_id'] = $orderTypeId;
            $payload['status_id'] = $statusId;
            $payload['carrier_id'] = $carrierId;

            $payload['province_id'] = $provinceId;
            $payload['canton_id'] = $cantonId;
            $payload['district_id'] = $districtId;

            unset($payload['channel'], $payload['order_type'], $payload['status'], $payload['carrier']);
            unset($payload['province'], $payload['canton'], $payload['district']);

            if (! empty($payload['store_id']) && blank($payload['store_name'] ?? null)) {
                $store = Store::query()->find($payload['store_id']);
                $payload['store_name'] = $store?->name;
            }

            /** @var Order $order */
            $order = Order::query()->create($payload);

            $order->details()->createMany($details);

            $order->load('details');

            $sumTI = (float) $order->details->sum('total_priceTI');
            $sumTE = (float) $order->details->sum('total_priceTE');

            $order->forceFill([
                'total_productsTI' => $sumTI,
                'total_productsTE' => $sumTE,
                'total_paidTI' => $sumTI + (float) $order->total_shipping - (float) $order->total_discounts,
                'total_paidTE' => $sumTE + (float) $order->total_shipping - (float) $order->total_discounts,
            ])->save();

            $order->statusLogs()->create([
                'status' => $statusCode,
                'note' => 'Creación desde WebFace',
                'happened_at' => now(),
            ]);

            return $order;
        });

        SyncOrderToOmsJob::dispatch($order->order_reference)->afterResponse();

        return response()->json([
            'message' => 'Order created.',
            'order_reference' => $order->order_reference,
            'id_order' => $order->id_order,
        ], 201);
    }

    public function updateStatus(UpdateOrderStatusRequest $request, string $orderReference): JsonResponse
    {
        $payload = $request->validated();

        $order = Order::query()->where('order_reference', $orderReference)->first();
        if (! $order) {
            return response()->json([
                'message' => 'Order not found.',
            ], 404);
        }

        $statusId = OrderStatusCatalog::query()->where('code', $payload['status'])->value('id_order_status');
        if (! $statusId) {
            return response()->json([
                'message' => 'Invalid status.',
            ], 422);
        }

        $order->forceFill(['status_id' => $statusId])->save();

        $order->statusLogs()->create([
            'status' => $payload['status'],
            'note' => $payload['note'] ?? null,
            'happened_at' => now(),
        ]);

        SyncOrderToOmsJob::dispatch($order->order_reference)->afterResponse();

        return response()->json([
            'message' => 'Status updated.',
            'order_reference' => $order->order_reference,
            'status' => $payload['status'],
        ], 200);
    }

    public function reprocess(string $orderReference): JsonResponse
    {
        $order = Order::query()->where('order_reference', $orderReference)->first();
        if (! $order) {
            return response()->json([
                'message' => 'Order not found.',
            ], 404);
        }

        SyncOrderToOmsJob::dispatch($order->order_reference)->afterResponse();

        return response()->json([
            'message' => 'Reprocess queued.',
            'order_reference' => $order->order_reference,
        ], 202);
    }
}
