<?php

namespace App\Services;

use App\Models\Franchise;
use App\Models\FranchiseTransaction;
use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\DB;

class FranchiseCommissionService
{
    public function __construct(
        private readonly FranchiseNotificationService $notificationService,
        private readonly FranchiseCommissionEngineService $commissionEngine
    )
    {
    }

    public function creditForOrder(Franchise $franchise, Order $order): ?FranchiseTransaction
    {
        $existing = FranchiseTransaction::query()
            ->where('franchise_id', $franchise->id)
            ->where('order_id', $order->id)
            ->where('transaction_type', 'commission_credit')
            ->exists();

        if ($existing) {
            return null;
        }

        $calc = $this->commissionEngine->calculate($franchise, 'sale_margin', (float) $order->total);
        $amount = (float) $calc['amount'];

        if ($amount <= 0) {
            return null;
        }

        return DB::transaction(function () use ($franchise, $order, $amount): FranchiseTransaction {
            $locked = Franchise::query()->whereKey($franchise->id)->lockForUpdate()->first();
            $locked->wallet_balance = round(((float) $locked->wallet_balance) + $amount, 2);
            $locked->save();

            $transaction = FranchiseTransaction::query()->create([
                'franchise_id' => $franchise->id,
                'order_id' => $order->id,
                'transaction_type' => 'commission_credit',
                'amount' => $amount,
                'bv' => 0,
                'quantity' => 0,
                'reference' => $order->order_number,
                'narration' => 'Sale margin commission credited',
                'transacted_at' => now(),
                'created_by' => $order->approved_by,
            ]);

            $this->notificationService->notify(
                $franchise,
                'Commission credited',
                "Sale margin commission of INR {$amount} credited for order {$order->order_number}.",
                route('franchise.commission')
            );

            return $transaction;
        });
    }

    public function reverseForOrder(Franchise $franchise, Order $order): ?FranchiseTransaction
    {
        $existing = FranchiseTransaction::query()
            ->where('franchise_id', $franchise->id)
            ->where('order_id', $order->id)
            ->where('transaction_type', 'commission_debit')
            ->exists();

        if ($existing) {
            return null;
        }

        $calc = $this->commissionEngine->calculate($franchise, 'sale_margin', (float) $order->total);
        $amount = (float) $calc['amount'];

        if ($amount <= 0) {
            return null;
        }

        return DB::transaction(function () use ($franchise, $order, $amount): FranchiseTransaction {
            $locked = Franchise::query()->whereKey($franchise->id)->lockForUpdate()->first();
            $locked->wallet_balance = max(0, round(((float) $locked->wallet_balance) - $amount, 2));
            $locked->save();

            return FranchiseTransaction::query()->create([
                'franchise_id' => $franchise->id,
                'order_id' => $order->id,
                'transaction_type' => 'commission_debit',
                'amount' => $amount,
                'bv' => 0,
                'quantity' => 0,
                'reference' => $order->order_number,
                'narration' => 'Sale margin commission reversal',
                'transacted_at' => now(),
                'created_by' => $order->approved_by,
            ]);
        });
    }

    public function creditForActivation(Franchise $franchise, User $newUser, float $packageAmount, ?int $createdBy = null): ?FranchiseTransaction
    {
        $reference = 'ACT-'.$newUser->member_code;

        $alreadyCredited = FranchiseTransaction::query()
            ->where('franchise_id', $franchise->id)
            ->where('reference', $reference)
            ->where('transaction_type', 'commission_credit')
            ->exists();

        if ($alreadyCredited) {
            return null;
        }

        $calc = $this->commissionEngine->calculate($franchise, 'id_activation', $packageAmount);
        $amount = (float) $calc['amount'];

        if ($amount <= 0) {
            return null;
        }

        return DB::transaction(function () use ($franchise, $newUser, $amount, $reference, $createdBy): FranchiseTransaction {
            $locked = Franchise::query()->whereKey($franchise->id)->lockForUpdate()->first();
            $locked->wallet_balance = round(((float) $locked->wallet_balance) + $amount, 2);
            $locked->save();

            $transaction = FranchiseTransaction::query()->create([
                'franchise_id' => $franchise->id,
                'user_id' => $newUser->id,
                'transaction_type' => 'commission_credit',
                'amount' => $amount,
                'bv' => 0,
                'quantity' => 0,
                'reference' => $reference,
                'narration' => 'ID activation commission credited',
                'transacted_at' => now(),
                'created_by' => $createdBy,
            ]);

            $this->notificationService->notify(
                $franchise,
                'Activation commission credited',
                "INR {$amount} credited for new ID {$newUser->member_code}.",
                route('franchise.commission')
            );

            return $transaction;
        });
    }

    public function creditForPickup(Order $order, ?int $createdBy = null): ?FranchiseTransaction
    {
        if (! $order->franchise_id) {
            return null;
        }

        $franchise = Franchise::query()->find($order->franchise_id);
        if (! $franchise) {
            return null;
        }

        $reference = 'PKP-'.$order->order_number;
        $exists = FranchiseTransaction::query()
            ->where('franchise_id', $franchise->id)
            ->where('reference', $reference)
            ->where('transaction_type', 'commission_credit')
            ->exists();

        if ($exists) {
            return null;
        }

        $calc = $this->commissionEngine->calculate($franchise, 'pickup_fee', (float) $order->total);
        $amount = (float) $calc['amount'];
        if ($amount <= 0) {
            return null;
        }

        return DB::transaction(function () use ($franchise, $order, $amount, $reference, $createdBy): FranchiseTransaction {
            $locked = Franchise::query()->whereKey($franchise->id)->lockForUpdate()->first();
            $locked->wallet_balance = round(((float) $locked->wallet_balance) + $amount, 2);
            $locked->save();

            $transaction = FranchiseTransaction::query()->create([
                'franchise_id' => $franchise->id,
                'order_id' => $order->id,
                'transaction_type' => 'commission_credit',
                'amount' => $amount,
                'bv' => 0,
                'quantity' => 0,
                'reference' => $reference,
                'narration' => 'Pickup handling fee credited',
                'transacted_at' => now(),
                'created_by' => $createdBy,
            ]);

            $this->notificationService->notify(
                $franchise,
                'Pickup fee credited',
                "INR {$amount} pickup handling fee credited for {$order->order_number}.",
                route('franchise.commission')
            );

            return $transaction;
        });
    }
}

