<?php

namespace MtcPharmacy\ReferAFriend\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Mtc\Modules\Members\Classes\Auth;
use Mtc\Modules\Members\Models\Member;
use MtcPharmacy\ReferAFriend\Classes\ReferralService;
use MtcPharmacy\ReferAFriend\Models\Referral;
use MtcPharmacy\ReferAFriend\Models\ReferralReward;

class ReferralsController extends Controller
{
    public function index(Request $request)
    {
        $member = Auth::getLoggedInMember();
        if (!$member || !$member->id) {
            return redirect('/members/login?redirect=/members/referrals');
        }

        // Get or create a referral code for this member's share link
        $referralCode = $this->getMemberReferralCode($member);
        $referralLink = config('app.url') . '/refer-a-friend/' . $referralCode;

        // Query data for dashboard
        $rewards = ReferralReward::available($member->id)->get();
        $pendingCount = Referral::byReferrer($member->id)->pending()
            ->where('channel', '!=', 'copy_link')
            ->count();
        $totalEarned = ReferralReward::where('member_id', $member->id)
            ->whereIn('status', ['issued', 'redeemed'])
            ->sum('amount');
        $invitations = Referral::byReferrer($member->id)
            ->where('channel', '!=', 'copy_link')
            ->orderBy('created_at', 'desc')
            ->get();

        return template('referrals/members_tab.twig', [
            'referral_link'  => $referralLink,
            'referral_code'  => $referralCode,
            'rewards'        => $rewards,
            'pending_count'  => $pendingCount,
            'total_earned'   => $totalEarned,
            'invitations'    => $invitations,
            'member'         => $member,
            'page_meta'      => ['page_title' => 'Refer a Friend'],
        ]);
    }

    public function sendInvite(Request $request): JsonResponse
    {
        $member = Auth::getLoggedInMember();
        if (!$member || !$member->id) {
            return response()->json(['success' => false, 'message' => 'Please log in.'], 401);
        }

        $email = $request->input('email');
        $channel = $request->input('channel', 'email');

        if (!$email || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return response()->json(['success' => false, 'message' => 'Please enter a valid email address.'], 422);
        }

        try {
            $service = app(ReferralService::class);
            $service->createReferral($member, $email, $channel);

            return response()->json(['success' => true, 'message' => 'Invitation sent']);
        } catch (\InvalidArgumentException $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 422);
        }
    }

    public function sendReminder(Request $request): JsonResponse
    {
        $member = Auth::getLoggedInMember();
        if (!$member || !$member->id) {
            return response()->json(['success' => false, 'message' => 'Please log in.'], 401);
        }

        $referralId = $request->input('referral_id');
        $referral = Referral::where('id', $referralId)
            ->where('referrer_id', $member->id)
            ->pending()
            ->first();

        if (!$referral) {
            return response()->json(['success' => false, 'message' => 'Referral not found.'], 422);
        }

        if ($referral->reminder_sent_at) {
            return response()->json(['success' => false, 'message' => 'Reminder already sent for this invitation.'], 422);
        }

        $service = app(ReferralService::class);
        $service->sendReminder($referral);

        return response()->json(['success' => true, 'message' => 'Reminder sent']);
    }

    public function getShareLink(Request $request): JsonResponse
    {
        $member = Auth::getLoggedInMember();
        if (!$member || !$member->id) {
            return response()->json(['success' => false, 'message' => 'Please log in.'], 401);
        }

        $code = $this->getMemberReferralCode($member);

        return response()->json([
            'link' => config('app.url') . '/refer-a-friend/' . $code,
            'code' => $code,
        ]);
    }

    protected function getMemberReferralCode(Member $member): string
    {
        // Two parallel requests in the same millisecond could both create a
        // pending row here. The harm is one extra unused row, so we don't
        // serialise — a lockForUpdate on the parent member row caused FK
        // validation to deadlock on the referrals insert.
        $referral = Referral::where('referrer_id', $member->id)
            ->where('channel', 'copy_link')
            ->where('status', 'pending')
            ->orderBy('id', 'desc')
            ->first();

        if (!$referral) {
            $referral = Referral::create([
                'referrer_id'   => $member->id,
                'channel'       => 'copy_link',
                'status'        => 'pending',
                'referee_email' => 'share-link@placeholder.local',
                'referral_code' => Referral::generateCode(),
                'expires_at'    => now()->addDays(config('referrals.link_expiry_days')),
            ]);
        }

        // Refresh expired code atomically — WHERE clause guards against
        // a stale row being updated twice.
        $updated = Referral::where('id', $referral->id)
            ->whereNotNull('expires_at')
            ->where('expires_at', '<', now())
            ->update([
                'referral_code' => Referral::generateCode(),
                'expires_at'    => now()->addDays(config('referrals.link_expiry_days')),
            ]);

        if ($updated) {
            $referral->refresh();
        }

        return $referral->referral_code;
    }
}
