<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\BalanceLog;
use App\Models\GmailSale;
use App\Models\GmailSellSetting;
use App\Models\IncomeHistory;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Schema;

class UserGmailSaleController extends Controller
{
    private const ALLOWED_STATUSES = ['all', 'pending', 'checked', 'rejected', 'completed'];

    public function history(Request $request, $status = null)
    {
        $user = auth()->user();
        $status = $this->normalizedStatus($status);
        $gmailSetting = GmailSellSetting::query()->first();
        $fallbackRate = round((float) ($gmailSetting->price ?? 0), 2);
        $statsResetAt = $this->gmailStatsResetAt($gmailSetting);

        $allSales = GmailSale::query()
            ->where('user_id', $user->id)
            ->latest('id')
            ->get();

        $saleMetrics = $this->buildSaleMetricsMap($allSales, $fallbackRate);
        $statusCounts = $this->buildStatusCounts($allSales);
        $countedSales = $this->gmailSalesAfterReset($allSales, $statsResetAt);
        $summary = $this->buildSummary($countedSales, $saleMetrics, $this->buildStatusCounts($countedSales));

        $filteredSales = $allSales
            ->when($status !== 'all', function (Collection $sales) use ($status) {
                return $sales->where('status', $status)->values();
            });

        $gmailSales = $this->paginateSalesCollection($filteredSales, $request, 18);

        $this->decorateSales($gmailSales, $saleMetrics);

        return view('user.gmail_sales_history', compact(
            'gmailSales',
            'status',
            'statusCounts',
            'summary',
            'statsResetAt'
        ));
    }

    private function normalizedStatus($status): string
    {
        $status = strtolower(trim((string) ($status ?? '')));

        return in_array($status, self::ALLOWED_STATUSES, true) ? $status : 'all';
    }

    private function buildStatusCounts(Collection $sales): array
    {
        $counts = [
            'all' => (int) $sales->count(),
            'pending' => 0,
            'checked' => 0,
            'rejected' => 0,
            'completed' => 0,
        ];

        foreach (['pending', 'checked', 'rejected', 'completed'] as $status) {
            $counts[$status] = (int) $sales->where('status', $status)->count();
        }

        return $counts;
    }

    private function buildSummary(Collection $sales, array $saleMetrics, array $statusCounts): array
    {
        $totalCredited = 0.0;
        $totalReversed = 0.0;
        $totalNet = 0.0;

        foreach ($sales as $sale) {
            $metrics = $saleMetrics[(int) $sale->id] ?? $this->emptyMetricRow();
            $totalCredited += (float) ($metrics['credited_amount'] ?? 0);
            $totalReversed += (float) ($metrics['reversed_amount'] ?? 0);
            $totalNet += (float) ($metrics['net_amount'] ?? 0);
        }

        return [
            'total_submissions' => $statusCounts['all'] ?? 0,
            'completed_count' => $statusCounts['completed'] ?? 0,
            'total_credited' => round($totalCredited, 2),
            'total_reversed' => round($totalReversed, 2),
            'net_profit' => round($totalNet, 2),
        ];
    }

    private function decorateSales(LengthAwarePaginator $gmailSales, array $saleMetrics): void
    {
        $gmailSales->setCollection(
            collect($gmailSales->items())->map(function (GmailSale $sale) use ($saleMetrics) {
                $metrics = $saleMetrics[(int) $sale->id] ?? $this->emptyMetricRow();

                $sale->setAttribute('display_rate_label', $this->formatMoney((float) ($metrics['listed_rate'] ?? 0)));
                $sale->setAttribute('is_rate_estimated', (bool) ($metrics['rate_is_estimated'] ?? false));
                $sale->setAttribute('credited_amount', (float) ($metrics['credited_amount'] ?? 0));
                $sale->setAttribute('reversed_amount', (float) ($metrics['reversed_amount'] ?? 0));
                $sale->setAttribute('net_amount', (float) ($metrics['net_amount'] ?? 0));
                $sale->setAttribute('history_note', (string) ($metrics['history_note'] ?? ''));

                return $sale;
            })
        );
    }

    private function buildSaleMetricsMap(Collection $sales, float $fallbackRate): array
    {
        if ($sales->isEmpty()) {
            return [];
        }

        $userId = (int) ($sales->first()->user_id ?? 0);
        $typedMap = $this->typedBalanceLogMapForUser($userId);
        $legacyMap = $this->legacyIncomeHistoryMapForUser($userId);
        $metrics = [];

        foreach ($sales as $sale) {
            $saleId = (int) $sale->id;
            $typed = $typedMap[$saleId] ?? ['credited' => 0.0, 'reversed' => 0.0];
            $legacy = $legacyMap[$saleId] ?? ['credited' => 0.0, 'reversed' => 0.0];
            $listedRate = round((float) ($sale->rate ?? $fallbackRate), 2);
            $credited = round(max((float) $typed['credited'], (float) $legacy['credited']), 2);
            $reversed = round(max((float) $typed['reversed'], (float) $legacy['reversed']), 2);

            if ($credited <= 0 && (string) $sale->status === 'completed') {
                $credited = $listedRate;
            }

            if ($credited <= 0 && $reversed > 0 && $listedRate > 0) {
                $credited = max($listedRate, $reversed);
            }

            $net = round($credited - $reversed, 2);

            $metrics[$saleId] = [
                'listed_rate' => $listedRate,
                'rate_is_estimated' => $sale->rate === null,
                'credited_amount' => $credited,
                'reversed_amount' => $reversed,
                'net_amount' => $net,
                'history_note' => $this->historyNoteForSale($sale, $credited, $reversed, $net),
            ];
        }

        return $metrics;
    }

    private function typedBalanceLogMapForUser(int $userId): array
    {
        if ($userId <= 0 || !$this->supportsTypedBalanceLogRewards()) {
            return [];
        }

        $rows = BalanceLog::query()
            ->where('user_id', $userId)
            ->where('type', 'like', 'gmail_sale_reward:%')
            ->get(['type', 'amount']);

        $map = [];

        foreach ($rows as $row) {
            if (preg_match('/^gmail_sale_reward:(\d+)$/', (string) ($row->type ?? ''), $matches) !== 1) {
                continue;
            }

            $saleId = (int) ($matches[1] ?? 0);
            if ($saleId <= 0) {
                continue;
            }

            if (!isset($map[$saleId])) {
                $map[$saleId] = ['credited' => 0.0, 'reversed' => 0.0];
            }

            $amount = round((float) ($row->amount ?? 0), 2);
            if ($amount >= 0) {
                $map[$saleId]['credited'] += $amount;
            } else {
                $map[$saleId]['reversed'] += abs($amount);
            }
        }

        return $map;
    }

    private function legacyIncomeHistoryMapForUser(int $userId): array
    {
        if ($userId <= 0 || !Schema::hasTable('income_histories')) {
            return [];
        }

        $rows = IncomeHistory::query()
            ->where('user_id', $userId)
            ->whereIn('source', ['gmail_sale', 'gmail_sale_reversal'])
            ->get(['source', 'amount', 'description']);

        $map = [];

        foreach ($rows as $row) {
            $saleId = $this->saleIdFromHistoryDescription((string) ($row->description ?? ''));
            if ($saleId <= 0) {
                continue;
            }

            if (!isset($map[$saleId])) {
                $map[$saleId] = ['credited' => 0.0, 'reversed' => 0.0];
            }

            $amount = round((float) ($row->amount ?? 0), 2);
            if ((string) $row->source === 'gmail_sale') {
                $map[$saleId]['credited'] += max($amount, 0);
            }

            if ((string) $row->source === 'gmail_sale_reversal') {
                $map[$saleId]['reversed'] += abs($amount);
            }
        }

        return $map;
    }

    private function saleIdFromHistoryDescription(string $description): int
    {
        if (preg_match('/submission\s*#(\d+)/i', $description, $matches) !== 1) {
            return 0;
        }

        return (int) ($matches[1] ?? 0);
    }

    private function historyNoteForSale(GmailSale $sale, float $credited, float $reversed, float $net): string
    {
        if ($reversed > 0) {
            return 'এই Gmail আগে sold হয়েছিল। পরে remove/reject হওয়ায় ' . $this->formatMoney($reversed) . ' সমন্বয় করা হয়েছে।';
        }

        if ((string) $sale->status === 'completed' && $net > 0) {
            return 'এই Gmail sale থেকে ' . $this->formatMoney($net) . ' আপনার balance-এ যোগ হয়েছে।';
        }

        if (in_array((string) $sale->status, ['pending', 'checked'], true)) {
            return 'এখনও এই Gmail sale-এর টাকা যোগ হয়নি। completed হলে ইনকাম যোগ হবে।';
        }

        if ((string) $sale->status === 'rejected') {
            return 'এই Gmail rejected হয়েছে। তাই কোনো ইনকাম যোগ হয়নি।';
        }

        if ($credited > 0) {
            return 'এই Gmail sale-এর হিসাব আপডেট হয়েছে।';
        }

        return 'এই Gmail sale-এর জন্য এখনো কোনো payout trail পাওয়া যায়নি।';
    }

    private function supportsTypedBalanceLogRewards(): bool
    {
        return Schema::hasTable('balance_logs') && Schema::hasColumn('balance_logs', 'type');
    }

    private function formatMoney(float $amount): string
    {
        return number_format($amount, 2) . ' ৳';
    }

    private function emptyMetricRow(): array
    {
        return [
            'listed_rate' => 0.0,
            'rate_is_estimated' => false,
            'credited_amount' => 0.0,
            'reversed_amount' => 0.0,
            'net_amount' => 0.0,
            'history_note' => '',
        ];
    }

    private function gmailStatsResetAt(?GmailSellSetting $setting): ?Carbon
    {
        $value = $setting ? $setting->getAttribute('stats_reset_at') : null;

        if (!$value && Schema::hasTable('gmail_sell_settings') && Schema::hasColumn('gmail_sell_settings', 'stats_reset_at')) {
            $value = GmailSellSetting::query()->whereNotNull('stats_reset_at')->value('stats_reset_at');
        }

        if (!$value) {
            return null;
        }

        return $value instanceof Carbon
            ? $value
            : Carbon::parse($value);
    }

    private function gmailSalesAfterReset(Collection $sales, ?Carbon $statsResetAt): Collection
    {
        if (!$statsResetAt) {
            return $sales->values();
        }

        return $sales->filter(function (GmailSale $sale) use ($statsResetAt) {
            if (!$sale->created_at) {
                return false;
            }

            return $sale->created_at->greaterThanOrEqualTo($statsResetAt);
        })->values();
    }

    private function paginateSalesCollection(Collection $sales, Request $request, int $perPage): LengthAwarePaginator
    {
        $page = max(1, (int) $request->query('page', 1));
        $items = $sales->slice(($page - 1) * $perPage, $perPage)->values();

        return new LengthAwarePaginator(
            $items,
            $sales->count(),
            $perPage,
            $page,
            [
                'path' => $request->url(),
                'query' => $request->query(),
            ]
        );
    }
}
