<?php

namespace App\Http\Controllers\Web;

use App\Http\Controllers\Controller;
use App\Core\Traits\CalculatesFees;
use App\Core\Traits\GeneratesReference;
use App\Models\BillService;
use App\Models\BillVariation;
use App\Modules\ProviderIntegration\Interfaces\ProviderInterface;
use App\Modules\Transactions\Interfaces\TransactionServiceInterface;
use App\Modules\Wallet\Interfaces\WalletServiceInterface;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class ElectricityController extends Controller
{
    use GeneratesReference, CalculatesFees;
    public function __construct(
        protected ProviderInterface $provider,
        protected TransactionServiceInterface $transactionService,
        protected WalletServiceInterface $walletService
    ) {}

    public function index()
    {
        $providers = BillService::active()->category('electricity')->get();
        return view('electricity.index', compact('providers'));
    }

    public function plans(string $provider)
    {
        $service = BillService::where('code', $provider)->active()->firstOrFail();
        $plans = BillVariation::where('bill_service_id', $service->id)->active()->orderBy('sort_order')->get();

        return response()->json(['plans' => $plans]);
    }

    public function validateMeter(Request $request)
    {
        $validated = $request->validate([
            'meter_number' => ['required', 'string'],
            'meter_type' => ['required', 'in:prepaid,postpaid'],
            'provider' => ['required', 'string'],
        ]);

        $service = BillService::where('code', $validated['provider'])->active()->firstOrFail();
        $variationCode = $validated['meter_type'] === 'prepaid' ? 'meter-prepaid' : 'meter-postpaid';

        try {
            $response = $this->provider->validateCustomer($service->code, $validated['meter_number'], $variationCode);
            return response()->json(['valid' => true, 'customer_data' => $response]);
        } catch (\Exception $e) {
            return response()->json(['valid' => false, 'message' => $e->getMessage()], 422);
        }
    }

    public function purchase(Request $request)
    {
        $validated = $request->validate([
            'meter_number' => ['required', 'string'],
            'meter_type' => ['required', 'in:prepaid,postpaid'],
            'provider' => ['required', 'string'],
            'variation_code' => ['required', 'string'],
            'amount' => ['required', 'numeric', 'min:100'],
            'phone' => ['nullable', 'string', 'max:20'],
        ]);

        $user = $request->user();
        $service = BillService::where('code', $validated['provider'])->active()->firstOrFail();
        $variation = BillVariation::where('code', $validated['variation_code'])->firstOrFail();
        $fee = $this->calculateFee($validated['amount'], (float) $service->service_charge, $service->category);
        $totalAmount = $validated['amount'] + $fee;
        $reference = 'ELC-' . strtoupper(Str::random(8)) . '-' . now()->format('YmdHis');

        if (!$this->checkDailyTransactionLimit($user->id)) {
            $message = 'Daily transaction limit reached. Please try again tomorrow.';
            if ($request->ajax()) {
                return response()->json(['success' => false, 'message' => $message], 422);
            }
            return back()->withErrors(['amount' => $message]);
        }

        try {
            DB::beginTransaction();

            if (!$this->walletService->canDebit($user->id, $totalAmount)) {
                DB::rollBack();
                if ($request->ajax()) {
                    return response()->json(['success' => false, 'message' => 'Insufficient wallet balance'], 422);
                }
                return back()->withErrors(['amount' => 'Insufficient wallet balance']);
            }

            $transaction = $this->transactionService->createTransaction([
                'user_id' => $user->id,
                'reference' => $reference,
                'bill_service_id' => $service->id,
                'bill_variation_id' => $variation->id,
                'type' => 'electricity',
                'service_name' => $service->name . ' - ' . ucfirst($validated['meter_type']),
                'network' => $service->code,
                'customer_number' => $validated['meter_number'],
                'amount' => $validated['amount'],
                'fee' => $fee,
                'total_amount' => $totalAmount,
                'ip_address' => $request->ip(),
                'device' => $request->userAgent(),
            ]);

            $this->walletService->debitWallet($user->id, $totalAmount, "Electricity purchase - {$service->name}", $reference, 'transaction', $transaction->id);
            $this->transactionService->markProcessing($reference);
            DB::commit();

            $requestId = self::generateVTPassRequestId();

            try {
                $response = $this->provider->purchaseElectricity(
                    $validated['meter_number'],
                    $service->code,
                    $validated['variation_code'],
                    $validated['amount'],
                    $validated['phone'] ?? $user->phone ?? '',
                    $requestId
                );
                if (isset($response['code']) && $response['code'] === '000') {
                    $tokenData = [
                        'token' => $response['mainToken'] ?? $response['purchased_code'] ?? null,
                        'exchange_reference' => $response['exchangeReference'] ?? null,
                        'response_description' => $response['response_description'] ?? null,
                        'request_id' => $response['requestId'] ?? null,
                        'amount' => $response['amount'] ?? null,
                        'transaction_date' => $response['transaction_date'] ?? null,
                    ];
                    $this->transactionService->markSuccessful($reference, $response, $tokenData);
                } else {
                    $this->transactionService->markFailed($reference, $response['response_description'] ?? 'Failed', $response);
                    $this->walletService->refundWallet($user->id, $totalAmount, "Refund for failed electricity purchase {$reference}", 'RFD-' . strtoupper(Str::random(8)));
                }
            } catch (\Exception $e) {
                $this->transactionService->markFailed($reference, $e->getMessage(), []);
                $this->walletService->refundWallet($user->id, $totalAmount, "Refund for failed electricity purchase {$reference}", 'RFD-' . strtoupper(Str::random(8)));
            }

            if ($request->ajax()) {
                return response()->json(['success' => true, 'message' => 'Electricity purchase submitted!', 'redirect' => route('transactions.show', $reference)]);
            }
            return redirect()->route('transactions.show', $reference)->with('success', 'Electricity purchase submitted!');
        } catch (\Exception $e) {
            DB::rollBack();
            if ($request->ajax()) {
                return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
            }
            return back()->withErrors(['error' => $e->getMessage()]);
        }
    }
}
