<?php

namespace Modules\PaynowGateway\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Modules\PaynowGateway\Services\PaynowService;
use App\Models\Subscription;
use App\Models\User;
use App\Services\CreditService;
use App\Services\WalletService;
// use Spatie\Permission\Models\Role; // If using roles and it's not auto-discovered

class PaynowWebhookController extends Controller
{
    protected PaynowService $paynowService;
    protected WalletService $walletService;
    protected CreditService $creditService;

    public function __construct(
        PaynowService $paynowService,
        WalletService $walletService,
        CreditService $creditService
    ) {
        $this->paynowService = $paynowService;
        $this->walletService = $walletService;
        $this->creditService = $creditService;
    }

    public function handleWebhook(Request $request)
    {
        $payload = $request->all(); // Paynow typically POSTs form data for webhooks
        Log::info('Paynow Webhook Received (raw):', $payload);

        $webhookProcessingResult = $this->paynowService->processWebhook($payload);

        if (!$webhookProcessingResult['verified']) {
            Log::warning('Paynow Webhook: Verification failed (e.g., invalid hash).', [
                'payload' => $payload, 'result' => $webhookProcessingResult
            ]);
            return response()->json(['status' => 'error', 'message' => $webhookProcessingResult['message'] ?? 'Webhook verification failed'], 400);
        }

        Log::info('Paynow Webhook Processed Data:', $webhookProcessingResult);

        $transactionReference = $webhookProcessingResult['external_reference'];
        $paynowReference = $webhookProcessingResult['paynow_reference'];
        $status = strtolower($webhookProcessingResult['status']); // Ensure lowercase for consistent comparison
        $pollUrl = $webhookProcessingResult['poll_url'];

        if (!$transactionReference) {
            Log::error('Paynow Webhook: Missing transaction reference in processed data.');
            return response()->json(['status' => 'error', 'message' => 'Missing reference'], 400);
        }

        if (Str::startsWith($transactionReference, 'SUB-')) {
            $this->handleSubscriptionWebhook($transactionReference, $paynowReference, $status, $pollUrl, $webhookProcessingResult);
        } elseif (Str::startsWith($transactionReference, 'WLT-')) {
            $this->handleWalletWebhook($transactionReference, $paynowReference, $status, $pollUrl, $webhookProcessingResult);
        } else {
            Log::info("Paynow Webhook: Unhandled transaction type for reference '{$transactionReference}'");
        }

        return response()->json(['status' => 'success', 'message' => 'Webhook received'], 200);
    }

    protected function handleSubscriptionWebhook($localRef, $paynowRef, $eventStatus, $pollUrl, $webhookData)
    {
        $subscription = Subscription::where('gateway_transaction_id', $localRef)
                            ->orderBy('created_at', 'desc') // In case of retries or multiple attempts with same ref
                            ->first();

        if (!$subscription) {
            Log::warning("Paynow Webhook: Subscription not found for local reference '{$localRef}' or Paynow ref '{$paynowRef}'.");
            return;
        }

        // Idempotency check: If already active and webhook says 'paid', likely already processed.
        if (($subscription->status === 'active' || $subscription->status === 'trialing') && $eventStatus === 'paid') {
            Log::info("Paynow Webhook: Subscription {$subscription->id} already active/trialing. Ignoring 'paid' event for local ref '{$localRef}'.");
            // Optionally update poll_url or paynow_reference if they differ and are useful
            if ($pollUrl && $subscription->gateway_poll_url !== $pollUrl) {
                $subscription->gateway_poll_url = $pollUrl;
            }
            if ($paynowRef && $subscription->gateway_transaction_id !== $paynowRef && $subscription->gateway_transaction_id === $localRef) {
                 // If we stored localRef initially, update to Paynow's actual transaction ID if preferred
                // $subscription->gateway_transaction_id = $paynowRef;
            }
            if ($subscription->isDirty()) {
                $subscription->save();
            }
            return;
        }

        Log::info("Paynow Webhook: Processing subscription {$subscription->id} for event '{$eventStatus}'. Local ref '{$localRef}'.");

        $originalStatus = $subscription->status;

        switch ($eventStatus) {
            case 'paid': // This is a common success status from Paynow
            case 'delivered': // Another possible success status
                if ($originalStatus !== 'active' && $originalStatus !== 'trialing') {
                    $user = $subscription->user;
                    // Cancel other active/trialing subscriptions for the user
                    $user->subscriptions()->where('id', '!=', $subscription->id)->whereIn('status', ['active', 'trialing'])
                         ->update(['status' => 'cancelled', 'ends_at' => now(), 'cancelled_at' => now()]);

                    $plan = $subscription->plan;
                    $subscription->status = $plan->trial_period_days > 0 ? 'trialing' : 'active';
                    $subscription->starts_at = $subscription->starts_at ?? now(); // Keep existing if already set (e.g. by callback)
                    $subscription->trial_ends_at = $plan->trial_period_days > 0 ? ($subscription->trial_ends_at ?? now()->addDays($plan->trial_period_days)) : null;
                    $subscription->ends_at = $subscription->ends_at ?? now()->add($plan->interval, $plan->interval_count);

                    if (function_exists('setting') && setting('credits_system_enabled', '0') == '1' && $plan->credits_awarded_on_purchase > 0) {
                        // Consider adding an idempotency check for credit awarding if this webhook might re-trigger
                        $this->creditService->awardCredits($user, $plan->credits_awarded_on_purchase, 'award_subscription_purchase_webhook', "Credits for {$plan->name} (Webhook)", $subscription);
                    }
                    if (!empty($plan->target_role) && class_exists(\Spatie\Permission\Models\Role::class) && \Spatie\Permission\Models\Role::where('name', $plan->target_role)->where('guard_name', 'web')->exists()) {
                        $user->syncRoles([$plan->target_role]);
                    }
                    Log::info("Paynow Webhook: Subscription {$subscription->id} activated/updated via webhook.");
                }
                break;

            case 'cancelled': // User cancelled on Paynow, or merchant cancelled
            case 'failed':    // Payment failed
            case 'disputed':  // Payment disputed
                if ($originalStatus !== 'cancelled' && $originalStatus !== 'failed') {
                    $subscription->status = ($eventStatus === 'cancelled' || $eventStatus === 'disputed') ? 'cancelled' : 'failed';
                    if (!$subscription->ends_at || $subscription->ends_at->isFuture()) {
                        $subscription->ends_at = now();
                    }
                    $subscription->cancelled_at = $subscription->cancelled_at ?? now();
                    Log::info("Paynow Webhook: Subscription {$subscription->id} status updated to '{$eventStatus}' via webhook.");
                }
                break;

            default:
                Log::info("Paynow Webhook: Unhandled subscription event status '{$eventStatus}' for subscription {$subscription->id}. Local ref '{$localRef}'.");
        }

        $subscription->gateway_poll_url = $pollUrl ?? $subscription->gateway_poll_url;
        // Update to Paynow's reference if it's different and we were using our local one
        // $subscription->gateway_transaction_id = $paynowRef ?? $localRef;
        $subscription->notes = ($subscription->notes ? $subscription->notes . " | " : "") . "Webhook: Status '{$eventStatus}'. PaynowRef: {$paynowRef}. LocalRef: {$localRef}.";
        if ($subscription->isDirty()) {
            $subscription->save();
        }
    }

    protected function handleWalletWebhook($localRef, $paynowRef, $eventStatus, $pollUrl, $webhookData)
    {
        Log::info("Paynow Webhook: Received wallet event '{$eventStatus}' for local reference '{$localRef}'. PaynowRef: '{$paynowRef}'.");
        // Wallet deposits are primarily handled by the synchronous callback for immediate user feedback.
        // Webhooks here serve as a reconciliation mechanism or handle cases where the user's browser
        // was closed before the callback was fully processed by your application.

        // Example: If you have a `wallet_transactions` table:
        // 1. Find the transaction by $localRef (and potentially $user_id if not globally unique).
        // 2. If its status is 'pending' and $eventStatus is 'paid' or 'delivered':
        //    - Mark your local transaction as 'completed'.
        //    - Credit the user's wallet using $this->walletService->deposit(...).
        //      Ensure this action is idempotent (doesn't credit twice if webhook is resent).
        //      You might check if a wallet credit with $paynowRef already exists.
        // 3. If its status is 'pending' and $eventStatus is 'failed'/'cancelled':
        //    - Mark your local transaction as 'failed'.

        // For now, this is a placeholder for more robust wallet webhook handling.
        // You would need a separate table to track individual wallet deposit attempts to make this robust.
        if ($eventStatus === 'paid' || $eventStatus === 'delivered') {
            // Potentially find user by email if $localRef doesn't directly link to a user or pending transaction
            // $user = User::where('email', $webhookData['raw_data']['authemail'] ?? null)->first();
            // if ($user) {
            //     $amount = (float) ($webhookData['amount'] ?? 0);
            //     $currency = setting('wallet_default_currency', 'USD'); // Assuming default
            //     // Check if this deposit was already processed via callback
            //     // This requires a way to uniquely identify the deposit attempt.
            //     Log::info("Paynow Webhook: Potential wallet deposit success for {$localRef}. Amount: {$amount}. Implement robust handling.");
            // }
        }
    }
}