<?php

namespace App\Http\Controllers\Store;

use App\Http\Controllers\Controller;
use App\Models\Affiliate;
use App\Models\AffiliateClick;
use App\Models\AffiliateCommission;
use App\Models\AffiliateLink;
use App\Models\AffiliatePayout;
use App\Models\Client;
use App\Models\Setting;
use App\Http\Requests\Store\AffiliateActivateRequest;
use App\Http\Requests\Store\AffiliateLinkStoreRequest;
use App\Http\Requests\Store\AffiliateLinkUpdateRequest;
use App\Http\Requests\Store\AffiliatePayoutRequestRequest;
use App\Services\AffiliateService;
use App\Traits\HasActiveClient;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class AffiliateController extends Controller
{
    // PRC-242 — getActiveClient() now provided by HasActiveClient trait.
    use HasActiveClient;

    protected AffiliateService $affiliateService;

    public function __construct(AffiliateService $affiliateService)
    {
        $this->middleware('auth:client');
        $this->affiliateService = $affiliateService;
    }

    /**
     * Ensure affiliate feature is enabled.
     */
    protected function ensureAffiliateEnabled(): void
    {
        if (! Setting::getValue('enable_affiliate', false)) {
            abort(404);
        }
    }

    /**
     * Get affiliate for the active client or null.
     */
    protected function getClientAffiliate(): ?Affiliate
    {
        $client = $this->getActiveClient();

        return Affiliate::where('client_id', $client->id)->first();
    }

    /**
     * Affiliate dashboard - main page with summary stats.
     */
    public function dashboard()
    {
        $this->ensureAffiliateEnabled();

        $client = $this->getActiveClient();
        $affiliate = $this->getClientAffiliate();

        // If no affiliate, redirect to activation page
        if (! $affiliate) {
            return redirect()->route('store.auth.affiliate.activate');
        }

        app(\App\Core\Hook\HookBridge::class)->fireAction('ClientAreaPageAffiliates',
            app(\App\Core\Hook\HookBridge::class)->buildClientContext($client, [
                'affiliate_id' => $affiliate->id,
            ])
        );

        // If affiliate is not active, show status info
        if ($affiliate->status !== 'active') {
            return view('clientarea.affiliate.dashboard', [
                'affiliate' => $affiliate,
                'report' => null,
                'client' => $client,
            ]);
        }

        // Generate monthly report for current month
        $report = $this->affiliateService->generateMonthlyReport($affiliate, now());

        // Get commission rate info
        $defaultRate = (float) Setting::getValue('affiliate_earning_percentage', 10);
        $commissionRate = $affiliate->commission_rate > 0 ? (float) $affiliate->commission_rate : $defaultRate;

        return view('clientarea.affiliate.dashboard', [
            'affiliate' => $affiliate,
            'report' => $report,
            'client' => $client,
            'commissionRate' => $commissionRate,
        ]);
    }

    /**
     * Show activation form (only when not yet affiliate).
     */
    public function activate()
    {
        $this->ensureAffiliateEnabled();

        $client = $this->getActiveClient();
        $affiliate = $this->getClientAffiliate();

        // If already an affiliate, redirect to dashboard
        if ($affiliate) {
            return redirect()->route('store.auth.affiliate.dashboard');
        }

        $defaultRate = (float) Setting::getValue('affiliate_earning_percentage', 10);
        $bonusDeposit = (float) Setting::getValue('affiliate_bonus_deposit', 0);

        return view('clientarea.affiliate.activate', [
            'client' => $client,
            'defaultRate' => $defaultRate,
            'bonusDeposit' => $bonusDeposit,
        ]);
    }

    /**
     * Process activation request.
     */
    public function submitActivation(AffiliateActivateRequest $request)
    {
        $this->ensureAffiliateEnabled();

        $client = $this->getActiveClient();

        if ($this->getClientAffiliate()) {
            return redirect()->route('store.auth.affiliate.dashboard')
                ->with('info', __('store.affiliate_already_active'));
        }

        $affiliateContract = \App\Models\Contract::active()
            ->ofType(\App\Enums\ContractType::AFFILIATE_AGREEMENT)
            ->ordered()->first();

        $defaultRate = (float) Setting::getValue('affiliate_earning_percentage', 10);
        $minPayout = (float) Setting::getValue('affiliate_payout_amount', 50);

        $affiliate = Affiliate::create([
            'client_id' => $client->id,
            'referral_code' => Affiliate::generateReferralCode(),
            'status' => 'active',
            'commission_type' => 'percentage',
            'commission_rate' => $defaultRate,
            'minimum_payout' => $minPayout,
        ]);

        // Record agreement acceptance for legal audit (KVKK + commission terms)
        if ($affiliateContract && $request->boolean('affiliate_agreement_accepted')) {
            app(\App\Services\Contract\ContractAcceptanceService::class)->record(
                $client,
                $affiliateContract,
                \App\Enums\AcceptanceContext::AFFILIATE_SIGNUP,
                null,
                $request
            );
        }

        // Create a default link
        AffiliateLink::create([
            'affiliate_id' => $affiliate->id,
            'label' => __('store.affiliate_default_link_label'),
            'target_url' => url('/'),
            'is_active' => true,
        ]);

        // Apply bonus deposit if configured
        $this->affiliateService->applyBonusDeposit($affiliate);

        // PRC-622 Task 9 — eski doğrudan SendEmailJob('Affiliate Account Activated',
        // 'affiliate', …) çağrısı KIRIKTI: 'affiliate' entity tipi SendEmailJob
        // haritasında yok ("Unknown entity type" → mail hiç gitmiyordu).
        // Yerine hook + config/communication_events.php eşlemesi (entity
        // 'client' → alıcı client'ın kendisi).
        app(\App\Core\Hook\HookBridge::class)->fireAction('AffiliateActivation', [
            'affiliate_id' => $affiliate->id,
            'client_id' => $client->id,
            'client_name' => trim($client->first_name . ' ' . $client->last_name),
            'client_email' => $client->email,
            'referral_code' => $affiliate->referral_code,
        ]);

        // PRC-622 — 'Admin Affiliate Application Received' admin bildirimi
        // (config/communication_events.php eşlemesi).
        app(\App\Core\Hook\HookBridge::class)->fireAction('AffiliateApplicationReceived', [
            'affiliate_id' => $affiliate->id,
            'client_id' => $client->id,
            'client_name' => trim($client->first_name . ' ' . $client->last_name),
            'client_email' => $client->email,
            'referral_code' => $affiliate->referral_code,
        ]);

        return redirect()->route('store.auth.affiliate.dashboard')
            ->with('success', __('store.affiliate_activated_successfully'));
    }

    /**
     * List affiliate links.
     */
    public function links()
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return redirect()->route('store.auth.affiliate.dashboard');
        }

        $links = $affiliate->links()
            ->orderBy('created_at', 'desc')
            ->get();

        return view('clientarea.affiliate.links', [
            'affiliate' => $affiliate,
            'links' => $links,
        ]);
    }

    /**
     * Create new affiliate link (AJAX).
     */
    public function createLink(AffiliateLinkStoreRequest $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return response()->json(['success' => false, 'message' => __('store.affiliate_status_inactive')], 403);
        }

        $link = AffiliateLink::create([
            'affiliate_id' => $affiliate->id,
            'label' => $request->label,
            'target_url' => $request->target_url,
            'is_active' => true,
        ]);

        return response()->json([
            'success' => true,
            'message' => __('store.affiliate_link_created'),
            'link' => [
                'id' => $link->id,
                'label' => $link->label,
                'target_url' => $link->target_url,
                'referral_url' => $affiliate->getReferralUrl() . '&url=' . urlencode($link->target_url),
                'clicks' => 0,
                'unique_clicks' => 0,
                'conversions' => 0,
                'is_active' => $link->is_active,
                'created_at' => $link->created_at->format('Y-m-d H:i'),
            ],
        ]);
    }

    /**
     * Update affiliate link (AJAX).
     */
    public function updateLink(AffiliateLinkUpdateRequest $request, AffiliateLink $link)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $link->affiliate_id !== $affiliate->id) {
            return response()->json(['success' => false, 'message' => __('store.affiliate_unauthorized')], 403);
        }

        $link->update([
            'label' => $request->label,
            'target_url' => $request->target_url,
            'is_active' => $request->has('is_active') ? $request->boolean('is_active') : $link->is_active,
        ]);

        return response()->json([
            'success' => true,
            'message' => __('store.affiliate_link_updated'),
        ]);
    }

    /**
     * Delete affiliate link (AJAX).
     */
    public function deleteLink(AffiliateLink $link)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $link->affiliate_id !== $affiliate->id) {
            return response()->json(['success' => false, 'message' => __('store.affiliate_unauthorized')], 403);
        }

        $link->delete();

        return response()->json([
            'success' => true,
            'message' => __('store.affiliate_link_deleted'),
        ]);
    }

    /**
     * Statistics page with date filter.
     */
    public function stats(Request $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return redirect()->route('store.auth.affiliate.dashboard');
        }

        return view('clientarea.affiliate.stats', [
            'affiliate' => $affiliate,
        ]);
    }

    /**
     * AJAX data for charts/statistics.
     */
    public function statsData(Request $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return response()->json(['success' => false], 403);
        }

        $startDate = $request->input('start_date')
            ? Carbon::parse($request->input('start_date'))->startOfDay()
            : now()->subDays(30)->startOfDay();

        $endDate = $request->input('end_date')
            ? Carbon::parse($request->input('end_date'))->endOfDay()
            : now()->endOfDay();

        $linkIds = AffiliateLink::where('affiliate_id', $affiliate->id)->pluck('id');

        // Daily clicks data
        $dailyClicks = [];
        $dailyConversions = [];

        if ($linkIds->isNotEmpty()) {
            $dailyClicks = DB::table('affiliate_clicks')
                ->select(DB::raw('DATE(created_at) as date'), DB::raw('COUNT(*) as total'), DB::raw('SUM(CASE WHEN is_unique = 1 THEN 1 ELSE 0 END) as unique_count'))
                ->whereIn('affiliate_link_id', $linkIds)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->groupBy(DB::raw('DATE(created_at)'))
                ->orderBy('date')
                ->get()
                ->keyBy('date')
                ->toArray();
        }

        // Daily conversions
        $dailyConversions = AffiliateCommission::where('affiliate_id', $affiliate->id)
            ->select(DB::raw('DATE(created_at) as date'), DB::raw('COUNT(*) as total'), DB::raw('SUM(amount) as amount'))
            ->whereBetween('created_at', [$startDate, $endDate])
            ->groupBy(DB::raw('DATE(created_at)'))
            ->orderBy('date')
            ->get()
            ->keyBy('date')
            ->toArray();

        // Country breakdown
        $countryBreakdown = [];
        if ($linkIds->isNotEmpty()) {
            $countryBreakdown = DB::table('affiliate_clicks')
                ->select('country', DB::raw('COUNT(*) as total'), DB::raw('SUM(CASE WHEN is_unique = 1 THEN 1 ELSE 0 END) as unique_count'))
                ->whereIn('affiliate_link_id', $linkIds)
                ->whereBetween('created_at', [$startDate, $endDate])
                ->whereNotNull('country')
                ->groupBy('country')
                ->orderByDesc('total')
                ->limit(20)
                ->get()
                ->toArray();
        }

        // Build dates range for chart
        $dates = [];
        $clicksData = [];
        $uniqueClicksData = [];
        $conversionsData = [];
        $earningsData = [];

        $current = $startDate->copy();
        while ($current->lte($endDate)) {
            $dateStr = $current->format('Y-m-d');
            $dates[] = $dateStr;

            $clickRow = $dailyClicks[$dateStr] ?? null;
            $clicksData[] = $clickRow ? (int) $clickRow->total : 0;
            $uniqueClicksData[] = $clickRow ? (int) $clickRow->unique_count : 0;

            $convRow = $dailyConversions[$dateStr] ?? null;
            $conversionsData[] = $convRow ? (int) $convRow->total : 0;
            $earningsData[] = $convRow ? round((float) $convRow->amount, 2) : 0;

            $current->addDay();
        }

        // Summary totals
        $totalClicks = array_sum($clicksData);
        $totalUniqueClicks = array_sum($uniqueClicksData);
        $totalConversions = array_sum($conversionsData);
        $totalEarnings = array_sum($earningsData);
        $conversionRate = $totalUniqueClicks > 0 ? round(($totalConversions / $totalUniqueClicks) * 100, 2) : 0;

        return response()->json([
            'success' => true,
            'dates' => $dates,
            'clicks' => $clicksData,
            'unique_clicks' => $uniqueClicksData,
            'conversions' => $conversionsData,
            'earnings' => $earningsData,
            'country_breakdown' => $countryBreakdown,
            'summary' => [
                'total_clicks' => $totalClicks,
                'total_unique_clicks' => $totalUniqueClicks,
                'total_conversions' => $totalConversions,
                'total_earnings' => $totalEarnings,
                'conversion_rate' => $conversionRate,
            ],
        ]);
    }

    /**
     * Commissions list page with KVKK masking.
     */
    public function commissions(Request $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return redirect()->route('store.auth.affiliate.dashboard');
        }

        return view('clientarea.affiliate.commissions', [
            'affiliate' => $affiliate,
        ]);
    }

    /**
     * DataTable records API for commissions.
     */
    public function commissionRecords(Request $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate) {
            return response()->json(['data' => [], 'recordsTotal' => 0, 'recordsFiltered' => 0]);
        }

        $query = AffiliateCommission::where('affiliate_id', $affiliate->id)
            ->with(['client', 'product', 'invoice']);

        // Total count
        $totalRecords = $query->count();

        // Filtering
        $search = $request->input('search.value');
        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('status', 'like', "%{$search}%")
                    ->orWhere('type', 'like', "%{$search}%")
                    ->orWhere('amount', 'like', "%{$search}%");
            });
        }

        $filteredRecords = $query->count();

        // Sorting
        $orderColumn = $request->input('order.0.column', 0);
        $orderDir = $request->input('order.0.dir', 'desc');
        $columns = ['id', 'created_at', 'type', 'amount', 'commission_rate', 'status'];
        $sortBy = $columns[$orderColumn] ?? 'created_at';
        $query->orderBy($sortBy, $orderDir);

        // Pagination
        $start = (int) $request->input('start', 0);
        $length = (int) $request->input('length', 10);
        $records = $query->skip($start)->take($length)->get();

        $data = $records->map(function ($commission) {
            // KVKK masking for buyer info
            $buyerName = '';
            $buyerEmail = '';
            if ($commission->client) {
                $buyerName = $this->affiliateService->maskName(
                    $commission->client->first_name . ' ' . $commission->client->last_name
                );
                $buyerEmail = $this->affiliateService->maskEmail($commission->client->email);
            }

            $productName = $commission->product ? $commission->product->name : '-';

            $statusBadge = match ($commission->status) {
                'pending' => '<span class="badge bg-warning text-dark">' . __('store.affiliate_status_pending') . '</span>',
                'approved' => '<span class="badge bg-info">' . __('store.affiliate_status_approved') . '</span>',
                'paid' => '<span class="badge bg-success">' . __('store.affiliate_status_paid') . '</span>',
                'rejected', 'cancelled' => '<span class="badge bg-danger">' . __('store.affiliate_status_rejected') . '</span>',
                default => '<span class="badge bg-secondary">' . ucfirst($commission->status) . '</span>',
            };

            $typeBadge = match ($commission->type) {
                'initial' => '<span class="badge bg-primary">' . __('store.affiliate_commission_type_initial') . '</span>',
                'recurring' => '<span class="badge bg-info">' . __('store.affiliate_commission_type_recurring') . '</span>',
                default => '<span class="badge bg-secondary">' . ucfirst($commission->type) . '</span>',
            };

            return [
                'id' => $commission->id,
                'date' => $commission->created_at->format('Y-m-d H:i'),
                'buyer' => $buyerName . ($buyerEmail ? '<br><small class="text-muted">' . $buyerEmail . '</small>' : ''),
                'product' => e($productName),
                'type' => $typeBadge,
                'amount' => number_format($commission->amount, 2),
                'rate' => number_format($commission->commission_rate, 2) . '%',
                'status' => $statusBadge,
            ];
        });

        return response()->json([
            'draw' => (int) $request->input('draw', 1),
            'recordsTotal' => $totalRecords,
            'recordsFiltered' => $filteredRecords,
            'data' => $data,
        ]);
    }

    /**
     * Payouts page.
     */
    public function payouts()
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return redirect()->route('store.auth.affiliate.dashboard');
        }

        $minPayout = (float) Setting::getValue('affiliate_payout_amount', 50);

        return view('clientarea.affiliate.payouts', [
            'affiliate' => $affiliate,
            'minPayout' => $minPayout,
        ]);
    }

    /**
     * Request payout or transfer to credit.
     */
    public function requestPayout(AffiliatePayoutRequestRequest $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate || $affiliate->status !== 'active') {
            return redirect()->route('store.auth.affiliate.dashboard')
                ->with('error', __('store.affiliate_status_inactive'));
        }

        $amount = round((float) $request->amount, 2);
        $method = $request->method;

        try {
            $this->affiliateService->requestPayout($affiliate, $amount, $method);

            if ($method === 'credit') {
                return redirect()->route('store.auth.affiliate.payouts')
                    ->with('success', __('store.affiliate_credit_transferred'));
            }

            return redirect()->route('store.auth.affiliate.payouts')
                ->with('success', __('store.affiliate_payout_requested'));
        } catch (\InvalidArgumentException $e) {
            return redirect()->route('store.auth.affiliate.payouts')
                ->with('error', $e->getMessage());
        }
    }

    /**
     * DataTable records API for payouts.
     */
    public function payoutRecords(Request $request)
    {
        $this->ensureAffiliateEnabled();

        $affiliate = $this->getClientAffiliate();

        if (! $affiliate) {
            return response()->json(['data' => [], 'recordsTotal' => 0, 'recordsFiltered' => 0]);
        }

        $query = AffiliatePayout::where('affiliate_id', $affiliate->id);

        $totalRecords = $query->count();

        // Filtering
        $search = $request->input('search.value');
        if ($search) {
            $query->where(function ($q) use ($search) {
                $q->where('status', 'like', "%{$search}%")
                    ->orWhere('method', 'like', "%{$search}%")
                    ->orWhere('amount', 'like', "%{$search}%");
            });
        }

        $filteredRecords = $query->count();

        // Sorting
        $orderColumn = $request->input('order.0.column', 0);
        $orderDir = $request->input('order.0.dir', 'desc');
        $columns = ['id', 'created_at', 'amount', 'method', 'status'];
        $sortBy = $columns[$orderColumn] ?? 'created_at';
        $query->orderBy($sortBy, $orderDir);

        // Pagination
        $start = (int) $request->input('start', 0);
        $length = (int) $request->input('length', 10);
        $records = $query->skip($start)->take($length)->get();

        $data = $records->map(function ($payout) {
            $statusBadge = match ($payout->status) {
                'pending' => '<span class="badge bg-warning text-dark">' . __('store.affiliate_status_pending') . '</span>',
                'paid' => '<span class="badge bg-success">' . __('store.affiliate_status_paid') . '</span>',
                'rejected' => '<span class="badge bg-danger">' . __('store.affiliate_status_rejected') . '</span>',
                default => '<span class="badge bg-secondary">' . ucfirst($payout->status) . '</span>',
            };

            $methodLabel = match ($payout->method) {
                'credit' => __('store.affiliate_method_credit'),
                'payout_request' => __('store.affiliate_method_payout_request'),
                default => ucfirst($payout->method ?? '-'),
            };

            return [
                'id' => $payout->id,
                'date' => $payout->created_at->format('Y-m-d H:i'),
                'amount' => number_format($payout->amount, 2),
                'method' => $methodLabel,
                'status' => $statusBadge,
                'paid_at' => $payout->paid_at ? $payout->paid_at->format('Y-m-d H:i') : '-',
                'notes' => e($payout->notes ?? '-'),
            ];
        });

        return response()->json([
            'draw' => (int) $request->input('draw', 1),
            'recordsTotal' => $totalRecords,
            'recordsFiltered' => $filteredRecords,
            'data' => $data,
        ]);
    }
}
