<?php

namespace App\Http\Controllers\Membership\Admin;

use App\Http\Controllers\Controller;
use App\Models\MembershipApplication;
use App\Models\MembershipCategory;
use App\Models\Member;
use App\Models\MemberActivityLog;
use App\Models\MembershipTransaction;
use App\Services\MembershipService;
use App\Services\MembershipCertificateService;
use App\Services\MembershipRenewalService;
use App\Services\PaymentService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;

class MembershipDashboardController extends Controller
{
    protected MembershipService $membershipService;
    protected MembershipCertificateService $certificateService;
    protected MembershipRenewalService $renewalService;
    protected PaymentService $paymentService;

    public function __construct(
        MembershipService $membershipService,
        MembershipCertificateService $certificateService,
        MembershipRenewalService $renewalService,
        PaymentService $paymentService
    ) {
        $this->membershipService  = $membershipService;
        $this->certificateService = $certificateService;
        $this->renewalService     = $renewalService;
        $this->paymentService     = $paymentService;
    }

    /**
     * Display the membership dashboard.
     */
    public function index()
    {
        abort_unless(auth()->user()->can('view members'), 403);

        $statistics = $this->membershipService->getStatistics();
        
        $pendingApplications = MembershipApplication::pending()
            ->with('membershipCategory')
            ->latest()
            ->take(10)
            ->get();

        $recentMembers = Member::with(['user', 'membershipCategories'])
            ->latest()
            ->take(10)
            ->get();

        $categories = MembershipCategory::withCount('members')->get();

        return view('membership.admin.dashboard', compact(
            'statistics',
            'pendingApplications',
            'recentMembers',
            'categories'
        ));
    }

    /**
     * Display pending applications.
     */
    public function pendingApplications(Request $request)
    {
        abort_unless(auth()->user()->can('view members'), 403);

        $query = MembershipApplication::with('membershipCategory')
            ->whereIn('status', ['pending', 'under_review']);

        if ($request->search) {
            $query->where(function ($q) use ($request) {
                $q->where('first_name', 'like', "%{$request->search}%")
                    ->orWhere('last_name', 'like', "%{$request->search}%")
                    ->orWhere('email', 'like', "%{$request->search}%")
                    ->orWhere('reference_number', 'like', "%{$request->search}%");
            });
        }

        if ($request->category_id) {
            $query->where('membership_category_id', $request->category_id);
        }

        $applications = $query->latest()->paginate(15);
        $categories = MembershipCategory::all();

        return view('membership.admin.applications.index', compact('applications', 'categories'));
    }

    /**
     * Display application details.
     */
    public function showApplication(MembershipApplication $application)
    {
        abort_unless(auth()->user()->can('view members'), 403);

        $application->load('membershipCategory');

        return view('membership.admin.applications.show', compact('application'));
    }

    /**
     * Approve an application.
     */
    public function approveApplication(Request $request, MembershipApplication $application)
    {
        abort_unless(auth()->user()->can('approve members'), 403);

        if (!$application->canBeApproved()) {
            return redirect()->back()
                ->withErrors(['error' => 'This application cannot be approved.']);
        }

        $member = $this->membershipService->createFromApplication($application, auth()->id());

        return redirect()->route('admin.members.show', $member)
            ->with('success', 'Application approved successfully. Member account created.');
    }

    /**
     * Reject an application.
     */
    public function rejectApplication(Request $request, MembershipApplication $application)
    {
        abort_unless(auth()->user()->can('approve members'), 403);

        $validator = Validator::make($request->all(), [
            'rejection_reason' => 'required|string|max:1000',
        ], [
            'rejection_reason.required' => 'Please provide a reason for rejection.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        if (!$application->canBeRejected()) {
            return redirect()->back()
                ->withErrors(['error' => 'This application cannot be rejected.']);
        }

        $application->update([
            'status' => 'rejected',
            'reviewed_by' => auth()->id(),
            'reviewed_at' => now(),
            'rejection_reason' => strip_tags($request->rejection_reason),
        ]);

        return redirect()->route('admin.members.applications.index')
            ->with('success', 'Application rejected.');
    }

    /**
     * Display all members.
     */
    public function members(Request $request)
    {
        abort_unless(auth()->user()->can('view members'), 403);

        $query = Member::with(['user', 'membershipCategories']);

        if ($request->search) {
            $query->whereHas('user', function ($q) use ($request) {
                $q->where('name', 'like', "%{$request->search}%")
                    ->orWhere('email', 'like', "%{$request->search}%");
            })->orWhere('membership_code', 'like', "%{$request->search}%");
        }

        if ($request->status) {
            $query->where('status', $request->status);
        }

        if ($request->category_id) {
            $query->whereHas('membershipCategories', function ($q) use ($request) {
                $q->where('membership_categories.id', $request->category_id);
            });
        }

        $members = $query->latest()->paginate(15);
        $categories = MembershipCategory::all();

        return view('membership.admin.members.index', compact('members', 'categories'));
    }

    /**
     * Display member details.
     */
    public function showMember(Member $member)
    {
        abort_unless(auth()->user()->can('view members'), 403);

        $member->load([
            'user',
            'membershipCategories',
            'contributions' => function ($query) {
                $query->latest()->take(10);
            },
            'loanApplications' => function ($query) {
                $query->latest()->take(5);
            },
            'certificates' => function ($query) {
                $query->latest()->take(5);
            },
            'renewals' => function ($query) {
                $query->with('certificate')->latest('renewed_at')->take(10);
            },
        ]);

        $currentCertificate = $member->currentCertificate();

        return view('membership.admin.members.show', compact('member', 'currentCertificate'));
    }

    /**
     * Show form to create a new member directly.
     */
    public function createMember()
    {
        abort_unless(auth()->user()->can('create members'), 403);

        $categories = MembershipCategory::active()->ordered()->get();

        return view('membership.admin.members.create', compact('categories'));
    }

    /**
     * Store a new member directly.
     */
    public function storeMember(Request $request)
    {
        abort_unless(auth()->user()->can('create members'), 403);

        $validator = Validator::make($request->all(), [
            'first_name' => 'required|string|max:191',
            'last_name' => 'required|string|max:191',
            'email' => 'required|email|max:191|unique:users,email',
            'phone' => 'nullable|string|max:20',
            'category_ids' => 'required|array|min:1',
            'category_ids.*' => 'exists:membership_categories,id',
            'status' => 'required|in:active,inactive,suspended',
            'notes' => 'nullable|string|max:1000',
        ], [
            'first_name.required' => 'First name is required.',
            'last_name.required' => 'Last name is required.',
            'email.required' => 'Email address is required.',
            'email.email' => 'Please enter a valid email address.',
            'email.unique' => 'A user with this email already exists.',
            'category_ids.required' => 'Please select at least one membership category.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator)
                ->withInput();
        }

        $validated = $validator->validated();
        $validated['first_name'] = strip_tags($validated['first_name']);
        $validated['last_name'] = strip_tags($validated['last_name']);
        $validated['notes'] = strip_tags($validated['notes'] ?? '');

        $member = $this->membershipService->createDirect($validated, auth()->id());

        return redirect()->route('admin.members.show', $member)
            ->with('success', 'Member created successfully.');
    }

    /**
     * Suspend a member.
     */
    public function suspendMember(Request $request, Member $member)
    {
        abort_unless(auth()->user()->can('edit members'), 403);

        $validator = Validator::make($request->all(), [
            'reason' => 'required|string|max:1000',
        ], [
            'reason.required' => 'Please provide a reason for suspension.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()
                ->withErrors($validator);
        }

        $this->membershipService->suspend($member, strip_tags($request->reason), auth()->id());

        return redirect()->route('admin.members.show', $member)
            ->with('success', 'Member suspended.');
    }

    /**
     * Reactivate a suspended member.
     */
    public function reactivateMember(Member $member)
    {
        abort_unless(auth()->user()->can('edit members'), 403);

        $this->membershipService->reactivate($member, auth()->id());

        return redirect()->route('admin.members.show', $member)
            ->with('success', 'Member reactivated.');
    }

    /**
     * Issue (regenerate) a certificate for a member — admin action.
     */
    public function issueCertificate(Member $member)
    {
        abort_unless(auth()->user()->can('issue membership certificates'), 403);

        try {
            $certificate = $this->certificateService->regenerateForMember($member);

            MemberActivityLog::log(
                'certificate_issued',
                "Certificate issued by admin: {$certificate->certificate_number}",
                $member,
                auth()->user(),
                ['certificate_id' => $certificate->id, 'certificate_number' => $certificate->certificate_number]
            );

            return redirect()->route('admin.members.show', $member)
                ->with('success', "Certificate {$certificate->certificate_number} issued and emailed to {$member->email}.");
        } catch (\Throwable $e) {
            return redirect()->route('admin.members.show', $member)
                ->withErrors(['error' => 'Certificate generation failed: ' . $e->getMessage()]);
        }
    }

    /**
     * Process a manual renewal on behalf of a member — admin action.
     */
    public function processRenewal(Member $member)
    {
        abort_unless(auth()->user()->can('edit members'), 403);

        if (!$member->isActive()) {
            return redirect()->route('admin.members.show', $member)
                ->withErrors(['error' => 'Only active members can be renewed.']);
        }

        try {
            $renewal = $this->renewalService->processRenewal($member, 'manual', auth()->id());

            MemberActivityLog::log(
                'membership_renewed',
                "Membership renewed by admin. New expiry: {$renewal->new_end_date->format('M j, Y')}",
                $member,
                auth()->user(),
                [
                    'renewal_id'        => $renewal->id,
                    'previous_end_date' => $renewal->previous_end_date?->toDateString(),
                    'new_end_date'      => $renewal->new_end_date->toDateString(),
                    'certificate_id'    => $renewal->certificate_id,
                ]
            );

            return redirect()->route('admin.members.show', $member)
                ->with('success', "Membership renewed. New expiry: {$renewal->new_end_date->format('F j, Y')}.");
        } catch (\Throwable $e) {
            return redirect()->route('admin.members.show', $member)
                ->withErrors(['error' => 'Renewal failed: ' . $e->getMessage()]);
        }
    }

    /**
     * Collect a renewal fee via MTN MoMo (mobile money or card).
     * Initiates a collection request and logs the transaction.
     */
    public function collectRenewalPayment(Request $request, Member $member)
    {
        abort_unless(auth()->user()->can('edit members'), 403);

        $paymentMethod = $request->input('payment_method', 'mobile_money');

        $rules = [
            'payment_method' => 'required|in:mobile_money,card',
            'amount'         => 'required|numeric|min:1',
            'currency'       => 'required|in:UGX,SSP,USD,KES',
            'payer_message'  => 'nullable|string|max:160',
        ];

        if ($paymentMethod === 'card') {
            $rules['card_number'] = 'required|string';
            $rules['card_expiry'] = ['required', 'regex:/^(0[1-9]|1[0-2])\/\d{2}$/'];
            $rules['card_cvv']    = 'required|digits_between:3,4';
        } else {
            $rules['phone_number'] = 'required|string|max:20';
        }

        $validator = Validator::make($request->all(), $rules, [
            'phone_number.required' => 'Phone number is required for mobile money payments.',
            'card_number.required'  => 'Card number is required.',
            'card_expiry.required'  => 'Card expiry date is required.',
            'card_cvv.required'     => 'CVV is required.',
            'amount.required'       => 'Amount is required.',
            'amount.min'            => 'Amount must be greater than zero.',
        ]);

        if ($validator->fails()) {
            return redirect()->back()->withErrors($validator)->withInput();
        }

        $reference    = 'RENEW-' . strtoupper($member->membership_code) . '-' . now()->format('YmdHis');
        $storedMethod = $paymentMethod === 'card' ? 'mtn_momo_card' : 'mtn_momo_mobile';
        $phoneNumber  = $paymentMethod !== 'card' ? $request->phone_number : null;

        // Initiate MTN MoMo collection (mobile or card)
        if ($paymentMethod === 'card') {
            $result = $this->paymentService->initiateCardCollection(
                cardNumber:   $request->card_number ?? '',
                expiry:       $request->card_expiry ?? '',
                cvv:          $request->card_cvv ?? '',
                amount:       (float) $request->amount,
                reference:    $reference,
                payerMessage: $request->payer_message ?? "Membership renewal — {$member->membership_code}",
                payeeNote:    "Renewal fee for member {$member->membership_code}"
            );
        } else {
            $result = $this->paymentService->initiateCollection(
                phoneNumber:  $request->phone_number,
                amount:       (float) $request->amount,
                reference:    $reference,
                payerMessage: $request->payer_message ?? "Membership renewal — {$member->membership_code}",
                payeeNote:    "Renewal fee for member {$member->membership_code}"
            );
        }

        // Record the transaction regardless of outcome
        MembershipTransaction::create([
            'transaction_reference' => $reference,
            'external_reference'    => $result['transaction_id'],
            'type'                  => 'renewal_fee',
            'member_id'             => $member->id,
            'amount'                => $request->amount,
            'currency'              => $request->currency,
            'payment_method'        => $storedMethod,
            'payment_phone'         => $phoneNumber,
            'status'                => $result['success'] ? 'pending' : 'failed',
            'initiated_at'          => now(),
            'error_message'         => $result['success'] ? null : $result['message'],
            'initiated_by'          => auth()->id(),
            'notes'                 => $request->payer_message,
        ]);

        MemberActivityLog::log(
            'renewal_payment_initiated',
            $result['success']
                ? "MTN MoMo renewal payment request sent. Ref: {$reference}"
                : "MTN MoMo renewal payment request failed. Ref: {$reference}",
            $member,
            auth()->user(),
            [
                'reference'      => $reference,
                'amount'         => $request->amount,
                'currency'       => $request->currency,
                'payment_method' => $storedMethod,
                'momo_result'    => $result,
            ]
        );

        if ($result['success']) {
            $target = $phoneNumber ?? '(card)';
            return redirect()->route('admin.members.show', $member)
                ->with('success', "Payment request sent to {$target}. Transaction ref: {$reference}. The member will receive a prompt to confirm.");
        }

        return redirect()->route('admin.members.show', $member)
            ->withErrors(['error' => 'Payment request failed: ' . $result['message']]);
    }
}
