<?php

namespace App\Http\Controllers\Customer;

use App\Http\Controllers\Controller;
use App\Http\Controllers\PaymentController;
use App\Models\Client;
use Brian2694\Toastr\Facades\Toastr;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class PayStationController extends Controller
{
    public function initiate(Request $request)
    {
        $request->validate([
            'customer_id' => ['required', 'integer'],
            'amount' => ['required', 'numeric', 'min:1'],
        ]);

        $merchantId = env('PAYSTATION_MERCHANT_ID');
        $password = env('PAYSTATION_PASSWORD');
        $baseUrl = rtrim(env('PAYSTATION_BASE_URL', 'https://api.paystation.com.bd'), '/');

        if (empty($merchantId) || empty($password)) {
            return response()->json([
                'status' => 'error',
                'message' => 'PayStation is not configured.',
            ], 422);
        }

        $customerId = (int) $request->input('customer_id');
        $client = Client::with(['clientsinfo', 'pop'])->find($customerId);
        if (!$client || optional($client->pop)->bill_generate !== 'yes') {
            return response()->json([
                'status' => 'error',
                'message' => 'Sorry user does not valid for payment.',
            ], 422);
        }

        $invoice = 'PS' . now()->format('YmdHis') . $client->id . Str::upper(Str::random(4));

        // PayStation's API expects an integer amount in BDT (no decimals).
        // If a decimal slips in from the UI, we reject it to avoid charging a different amount
        // than what we later validate against.
        $rawAmount = (float) $request->amount;
        if (abs($rawAmount - round($rawAmount)) > 0.00001) {
            return response()->json([
                'status' => 'error',
                'message' => 'PayStation amount must be a whole number (no decimals).',
            ], 422);
        }
        $amount = (float) ((int) round($rawAmount));

        DB::table('orders')->insert([
            'name' => $client->clientsinfo->clients_name ?? $client->userid,
            'email' => $client->clientsinfo->email ?? 'demo@example.com',
            'phone' => $client->clientsinfo->contact_no ?? '',
            'amount' => $amount,
            'address' => $client->clientsinfo->area ?? null,
            'status' => 'Pending',
            'transaction_id' => $invoice,
            'currency' => 'BDT',
            'customer_id' => $client->id,
            'created_at' => now(),
            'updated_at' => now(),
        ]);

        $callbackUrl = route('paystation.callback', ['invoice' => $invoice]);

        $payload = [
            'merchantId' => $merchantId,
            'password' => $password,
            'invoice_number' => $invoice,
            'currency' => 'BDT',
            'payment_amount' => (string) ((int) $amount),
            'pay_with_charge' => (int) (env('PAYSTATION_PAY_WITH_CHARGE', 1)),
            'reference' => 'Client Payment: ' . $client->userid,
            'cust_name' => $client->clientsinfo->clients_name ?? $client->userid,
            'cust_phone' => $client->clientsinfo->contact_no ?? '',
            'cust_email' => $client->clientsinfo->email ?? 'demo@example.com',
            'cust_address' => $client->clientsinfo->area ?? 'N/A',
            'callback_url' => $callbackUrl,
            'opt_a' => (string) $client->id,
            'opt_b' => (string) $client->slug,
        ];

        $resp = Http::asForm()
            ->timeout(30)
            ->post($baseUrl . '/initiate-payment', $payload);

        if (!$resp->ok()) {
            return response()->json([
                'status' => 'error',
                'message' => 'PayStation initiate failed.',
            ], 502);
        }

        $data = $resp->json();
        if (!is_array($data) || ($data['status'] ?? '') !== 'success' || empty($data['payment_url'])) {
            return response()->json([
                'status' => 'error',
                'message' => $data['message'] ?? 'PayStation initiate failed.',
            ], 422);
        }

        return response()->json([
            'status' => 'success',
            'payment_url' => $data['payment_url'],
            'invoice_number' => $invoice,
        ]);
    }

    public function callback(Request $request, string $invoice)
    {
        $status = $request->query('status');
        $invoiceFromGateway = $request->query('invoice_number');
        $trxId = $request->query('trx_id');

        if ($invoiceFromGateway && $invoiceFromGateway !== $invoice) {
            return redirect()->route('clientPaymentSearch')->with('error', 'Invalid PayStation callback.');
        }

        $order = DB::table('orders')->where('transaction_id', $invoice)->first();
        if (!$order) {
            return redirect()->route('clientPaymentSearch')->with('error', 'PayStation order not found.');
        }

        if (strtolower((string) $order->status) === 'complete') {
            $client = Client::find($order->customer_id);
            if ($client) {
                return redirect()->route('client-open-payment', $client->slug)->with('successMsg', 'Payment already completed.');
            }
            return redirect()->route('clientPaymentSearch')->with('successMsg', 'Payment already completed.');
        }

        if (!in_array($status, ['Successful', 'success', 'SUCCESS', 'Successful '], true)) {
            DB::table('orders')->where('transaction_id', $invoice)->update([
                'status' => 'Failed',
                'updated_at' => now(),
            ]);
            $client = Client::find($order->customer_id);
            if ($client) {
                return redirect()->route('client-open-payment', $client->slug)->with('error', 'Payment failed/canceled.');
            }
            return redirect()->route('clientPaymentSearch')->with('error', 'Payment failed/canceled.');
        }

        $merchantId = env('PAYSTATION_MERCHANT_ID');
        $baseUrl = rtrim(env('PAYSTATION_BASE_URL', 'https://api.paystation.com.bd'), '/');

        try {
            $verifyResp = Http::withHeaders(['merchantId' => $merchantId])
                ->asForm()
                ->timeout(30)
                ->post($baseUrl . '/transaction-status', [
                    'invoice_number' => $invoice,
                ]);
        } catch (\Throwable $e) {
            $verifyResp = null;
        }

        $verified = false;
        $verifiedAmount = null;
        $verifiedTrxId = $trxId;

        if ($verifyResp && $verifyResp->ok()) {
            $vr = $verifyResp->json();

            // Keep a copy of gateway verification payload for debugging/disputes.
            try {
                DB::table('orders')->where('transaction_id', $invoice)->update([
                    'ipn_data' => json_encode($vr, JSON_UNESCAPED_UNICODE),
                    'updated_at' => now(),
                ]);
            } catch (\Throwable $e) {
                // Best-effort only
            }

            $trxStatus = strtolower((string) data_get($vr, 'data.trx_status', ''));
            $rawVerifiedAmount = data_get($vr, 'data.payment_amount', 0);
            if (is_string($rawVerifiedAmount)) {
                $rawVerifiedAmount = preg_replace('/[^0-9.]/', '', $rawVerifiedAmount);
            }
            $verifiedAmount = (float) $rawVerifiedAmount;
            $verifiedTrxId = data_get($vr, 'data.trx_id', $trxId);
            $verified = in_array($trxStatus, ['success', 'successful', 'validated', 'valid'], true);
        }

        if (!$verified) {
            DB::table('orders')->where('transaction_id', $invoice)->update([
                'status' => 'Failed',
                'updated_at' => now(),
            ]);
            $client = Client::find($order->customer_id);
            if ($client) {
                return redirect()->route('client-open-payment', $client->slug)->with('error', 'Payment validation failed.');
            }
            return redirect()->route('clientPaymentSearch')->with('error', 'Payment validation failed.');
        }

        // Amount check (best-effort)
        $orderAmount = (float) $order->amount;
        if ($verifiedAmount !== null && $orderAmount > 0) {
            // PayStation can return bill + gateway charge (e.g. bill ৳1, paid ৳1.02).
            // We only fail if gateway paid amount is LESS than our expected bill amount.
            if ($verifiedAmount + 0.01 < $orderAmount) {
                DB::table('orders')->where('transaction_id', $invoice)->update([
                    'status' => 'Failed',
                    'updated_at' => now(),
                ]);
                $client = Client::find($order->customer_id);
                if ($client) {
                    return redirect()->route('client-open-payment', $client->slug)->with('error', 'Payment amount mismatch.');
                }
                return redirect()->route('clientPaymentSearch')->with('error', 'Payment amount mismatch.');
            }
        }

        DB::table('orders')->where('transaction_id', $invoice)->update([
            'status' => 'Processing',
            'updated_at' => now(),
        ]);

        $pc = app(PaymentController::class);
        $ok = $pc->paystationPaymentProcess((int) $order->customer_id, (float) $order->amount, (string) $verifiedTrxId, (string) $invoice);

        DB::table('orders')->where('transaction_id', $invoice)->update([
            'status' => $ok ? 'Complete' : 'Failed',
            'updated_at' => now(),
        ]);

        $client = Client::find($order->customer_id);
        if ($client) {
            return redirect()->route('client-open-payment', $client->slug)
                ->with($ok ? 'successMsg' : 'error', $ok ? 'Payment is Successful' : 'Payment failed.');
        }

        return redirect()->route('clientPaymentSearch')
            ->with($ok ? 'successMsg' : 'error', $ok ? 'Payment is Successful' : 'Payment failed.');
    }
}
