<?php

namespace App\Http\Controllers\Api\Mobile;

use App\Http\Controllers\Controller;
use App\Models\Coupon;
use App\Models\Plan;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

/**
 * Mobile-app coupon endpoints.
 *
 * The Flutter checkout screen calls /validate to preview a coupon's
 * effect on the displayed total. Actual redemption happens when the
 * mobile app passes `coupon_code` to /payments/initiate — the payment
 * flow re-validates server-side and increments `times_used` only on
 * a successful payment (same pattern as the web CheckoutController).
 *
 * Keeping validate and apply separate avoids the "user typed the code,
 * abandoned checkout, but times_used went up" footgun.
 */
class CouponsController extends Controller
{
    /**
     * GET /api/v1/mobile/coupons
     *
     * List currently valid, publicly-applicable coupons so the Flutter
     * checkout screen can show "available promos" without the user
     * needing to know a code. Only coupons that are:
     *   - is_active = true
     *   - expires_at in the future (or null)
     *   - haven't hit max_uses
     * are returned. Codes are exposed (they're meant to be redeemed) but
     * actual redemption still goes through /payments/initiate so we
     * never bump times_used here.
     *
     * Query:
     *   plan_id  (optional) — filter to coupons applicable to this plan
     */
    public function index(Request $request): JsonResponse
    {
        $planId = $request->integer('plan_id');

        $q = Coupon::query()
            ->where('is_active', true)
            ->where(function ($w) {
                $w->whereNull('expires_at')->orWhere('expires_at', '>', now());
            })
            ->where(function ($w) {
                // max_uses is nullable in the schema; null = unlimited.
                $w->whereNull('max_uses')->orWhereColumn('times_used', '<', 'max_uses');
            })
            ->orderByDesc('id');

        $rows = $q->get()
            ->filter(fn (Coupon $c) => !$planId || $c->isApplicableToPlan($planId))
            ->map(function (Coupon $c) {
                // Use the normalized helpers — see CouponsController::validateCode
                // for why: the table mixes legacy `value` rows with
                // Stripe-style `percent_off` / `amount_off` rows, and the
                // legacy `$c->value` is null for the latter.
                $kind = $c->discountKind();
                $value = $c->resolvedValue();
                return [
                    'code'        => $c->code,
                    'name'        => $c->name,
                    'type'        => $kind,                  // normalized: 'percent' | 'fixed'
                    'value'       => $value,                 // real number, never null
                    'currency'    => $c->currency,
                    'expires_at'  => $c->expires_at?->toIso8601String(),
                    'max_uses'    => $c->max_uses,
                    'times_used'  => $c->times_used,
                    'description' => $kind === 'percent'
                        ? "{$value}% off"
                        : number_format($value, 2) . ' ' . ($c->currency ?: '') . ' off',
                ];
            })
            ->values();

        return response()->json([
            'success' => true,
            'data'    => $rows,
        ]);
    }

    /**
     * POST /api/v1/mobile/coupons/validate
     *
     * Body:
     *   code          (required) — coupon string, case-insensitive
     *   plan_id       (required) — the plan being purchased
     *   billing_cycle (optional) — monthly | yearly, default monthly
     */
    public function validateCode(Request $request): JsonResponse
    {
        $validator = Validator::make($request->all(), [
            'code'          => 'required|string|max:50',
            'plan_id'       => 'required|integer|exists:plans,id',
            'billing_cycle' => 'nullable|in:monthly,yearly',
        ]);

        if ($validator->fails()) {
            return response()->json([
                'valid'  => false,
                'errors' => $validator->errors(),
            ], 422);
        }

        $code = strtoupper(trim((string) $request->input('code')));
        $coupon = Coupon::where('code', $code)->first();

        if (!$coupon || !$coupon->isValid()) {
            return response()->json([
                'valid'   => false,
                'message' => 'Invalid or expired coupon code.',
            ]);
        }

        $plan = Plan::find($request->integer('plan_id'));
        if (!$plan) {
            return response()->json([
                'valid'   => false,
                'message' => 'Plan not found.',
            ], 404);
        }

        if (!$coupon->isApplicableToPlan($plan->id)) {
            return response()->json([
                'valid'   => false,
                'message' => 'This coupon is not applicable to the selected plan.',
            ]);
        }

        // Resolve the plan price for the requested billing cycle. Falls
        // back to monthly if the field is missing (some legacy plans
        // ship without a yearly price).
        $cycle = $request->input('billing_cycle', 'monthly');
        $originalAmount = (float) ($cycle === 'yearly'
            ? ($plan->yearly_price ?? $plan->monthly_price ?? 0)
            : ($plan->monthly_price ?? 0));

        $discountAmount = round($coupon->calculateDiscount($originalAmount), 2);
        $finalAmount    = round($coupon->getDiscountedPrice($originalAmount), 2);

        // Use the normalized helpers so the response is correct whether
        // the row was created via the legacy `value` column OR the
        // Stripe-style `percent_off` / `amount_off` columns.
        $kind = $coupon->discountKind();
        $value = $coupon->resolvedValue();

        return response()->json([
            'valid'          => true,
            'code'           => $coupon->code,
            'name'           => $coupon->name,
            'type'           => $kind,                          // normalized: 'percent' | 'fixed'
            'value'          => $value,                         // real number, never null
            'currency'       => $coupon->currency,
            'original_amount' => $originalAmount,
            'discount_amount' => $discountAmount,
            'final_amount'    => $finalAmount,
            'billing_cycle'   => $cycle,
            'message'        => $kind === 'percent'
                ? "{$value}% off"
                : number_format($value, 2) . ' ' . ($coupon->currency ?: '') . ' off',
        ]);
    }
}
