<?php

namespace App\Services;

use App\Models\User;
use App\Models\GmailSale;
use App\Models\FbSubmission;
use Illuminate\Support\Collection;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Schema;

class LeadershipService
{
    private function activeOrActivated($query, bool $keepAfterUnverify = true)
    {
        $hasLeadershipFlag = Schema::hasColumn('users', 'leadership_referral_enabled');

        if ($keepAfterUnverify) {
            $query->where(function ($q) {
                $q->where('is_active', 1)
                  ->orWhereNotNull('activated_at');
            });

            if ($hasLeadershipFlag) {
                $query->where(function ($q) {
                    $q->where('leadership_referral_enabled', 1)
                      ->orWhereNull('leadership_referral_enabled');
                });
            }

            return $query;
        }

        $query->where('is_active', 1);

        if ($hasLeadershipFlag) {
            $query->where(function ($q) {
                $q->where('leadership_referral_enabled', 1)
                  ->orWhereNull('leadership_referral_enabled');
            });
        }

        return $query;
    }

    private function applyStartFilter(Collection $members, ?Carbon $start): Collection
    {
        if (!$start) {
            return $members->values();
        }

        return $members
            ->filter(function ($member) use ($start) {
                $effectiveAt = $this->leadershipCountStartsAt($member);

                return $effectiveAt instanceof Carbon && $effectiveAt->gt($start);
            })
            ->values();
    }

    /**
     * Level 1 = direct referrals
     */
    public function level1(User $user, ?Carbon $start = null, bool $keepAfterUnverify = true): Collection
    {
        $code = (string)($user->referral_code ?? '');
        if (!$code) return collect();

        $query = User::where(function ($q) use ($code, $user) {
            $q->where('referred_by', $code)
              ->orWhere('referred_by', (string)$user->id);
        });

        $members = $this->activeOrActivated($query, $keepAfterUnverify)
            ->get($this->levelSelectColumns());

        return $this->applyStartFilter($members, $start);
    }

    /**
     * Level 2 = referrals of level1
     */
    public function level2(User $user, ?Carbon $start = null, bool $keepAfterUnverify = true): Collection
    {
        $parents = $this->level1($user, null, $keepAfterUnverify);
        if ($parents->isEmpty()) return collect();

        $codes = $parents->pluck('referral_code')->filter()->values();
        $ids   = $parents->pluck('id')->map(fn ($i) => (string)$i)->values();

        $query = User::where(function ($q) use ($codes, $ids) {
            if ($codes->isNotEmpty()) $q->whereIn('referred_by', $codes);
            if ($ids->isNotEmpty())   $q->orWhereIn('referred_by', $ids);
        });

        $members = $this->activeOrActivated($query, $keepAfterUnverify)
            ->get($this->levelSelectColumns());

        return $this->applyStartFilter($members, $start);
    }

    /**
     * Level 3 = referrals of level2
     */
    public function level3(User $user, ?Carbon $start = null, bool $keepAfterUnverify = true): Collection
    {
        $parents = $this->level2($user, null, $keepAfterUnverify);
        if ($parents->isEmpty()) return collect();

        $codes = $parents->pluck('referral_code')->filter()->values();
        $ids   = $parents->pluck('id')->map(fn ($i) => (string)$i)->values();

        $query = User::where(function ($q) use ($codes, $ids) {
            if ($codes->isNotEmpty()) $q->whereIn('referred_by', $codes);
            if ($ids->isNotEmpty())   $q->orWhereIn('referred_by', $ids);
        });

        $members = $this->activeOrActivated($query, $keepAfterUnverify)
            ->get($this->levelSelectColumns());

        return $this->applyStartFilter($members, $start);
    }

    public function verifiedCountForRank(User $user, bool $incL2, bool $incL3, ?Carbon $start = null, bool $keepAfterUnverify = true): int
    {
        $l1 = $this->level1($user, $start, $keepAfterUnverify)->count();
        $total = $l1;
        if ($incL2) {
            $total += $this->level2($user, $start, $keepAfterUnverify)->count();
            if ($incL3) {
                $total += $this->level3($user, $start, $keepAfterUnverify)->count();
            }
        }
        return $total;
    }

    public function gmailCompletedCount(User $user): int
    {
        return GmailSale::where('user_id', $user->id)
            ->where('status', 'completed')
            ->count();
    }

    public function fbApprovedCount(User $user): int
    {
        return FbSubmission::where('user_id', $user->id)
            ->where('status', 'approved')
            ->count();
    }

    public function progress(User $user): array
    {
        $l1 = $this->level1($user);
        $l2 = $this->level2($user);
        $l3 = $this->level3($user);

        return [
            'verified'         => $l1->count(),
            'verified_level2'  => $l2->count(),
            'verified_level3'  => $l3->count(),
            'verified_total'   => $l1->count() + $l2->count() + $l3->count(),
            'gmail'            => $this->gmailCompletedCount($user),
            'fb'               => $this->fbApprovedCount($user),
            'level1_list'      => $l1,
            'level2_list'      => $l2,
            'level3_list'      => $l3,
        ];
    }

    private function levelSelectColumns(): array
    {
        $columns = ['id', 'referral_code', 'name', 'created_at', 'activated_at'];

        if (Schema::hasColumn('users', 'leadership_referral_enabled')) {
            $columns[] = 'leadership_referral_enabled';
        }

        if (Schema::hasColumn('users', 'leadership_referral_enabled_at')) {
            $columns[] = 'leadership_referral_enabled_at';
        }

        return $columns;
    }

    private function leadershipCountStartsAt(mixed $member): ?Carbon
    {
        $activatedAt = $this->normalizeDate(data_get($member, 'activated_at'));
        $createdAt = $this->normalizeDate(data_get($member, 'created_at'));
        $enabledAt = $this->normalizeDate(data_get($member, 'leadership_referral_enabled_at'));

        $effectiveAt = $activatedAt ?? $createdAt;
        if ($enabledAt instanceof Carbon && (!$effectiveAt || $enabledAt->gt($effectiveAt))) {
            return $enabledAt;
        }

        return $effectiveAt;
    }

    private function normalizeDate(mixed $value): ?Carbon
    {
        if ($value instanceof Carbon) {
            return $value;
        }

        if ($value instanceof \DateTimeInterface) {
            return Carbon::instance($value);
        }

        if ($value === null || $value === '') {
            return null;
        }

        try {
            return Carbon::parse($value);
        } catch (\Throwable $e) {
            return null;
        }
    }
}
