<?php

namespace App\Services;

use App\Models\ActivityLogModel;
use App\Models\BranchModel;
use App\Models\DepartmentModel;
use App\Models\PermissionModel;
use App\Models\RoleModel;
use Config\Database;
use Modules\Auth\Models\UserSessionModel;
use Modules\Documents\Services\DocumentExpiryService;

class DashboardService
{
    protected $db;

    public function __construct()
    {
        $this->db = Database::connect();
    }

    public function summary(): array
    {
        $activeUsers   = $this->countUsers(['status' => 'active']);
        $branchCount   = (new BranchModel())->where('status', 'active')->countAllResults();
        $deptCount     = (new DepartmentModel())->where('status', 'active')->countAllResults();
        $activity24h   = (new ActivityLogModel())
            ->where('created_at >=', date('Y-m-d H:i:s', strtotime('-24 hours')))
            ->countAllResults();
        $activeSessions = $this->countActiveSessions();
        $docExpiry     = (new DocumentExpiryService())->summary();

        return [
            'activeUsers'    => $activeUsers,
            'branches'       => $branchCount,
            'departments'    => $deptCount,
            'activity24h'    => $activity24h,
            'activeSessions' => $activeSessions,
            'documentExpiry' => $docExpiry,
        ];
    }

    public function kpis(): array
    {
        $totalUsers     = $this->countUsers();
        $activeUsers    = $this->countUsers(['status' => 'active']);
        $inactiveUsers  = $this->countUsers(['status' => 'inactive']);
        $lockedUsers    = $this->countUsers(['status' => 'locked']);
        $newThisMonth   = $this->countUsersCreatedSince(date('Y-m-01 00:00:00'));
        $rolesCount     = (new RoleModel())->countAllResults();
        $permissions    = (new PermissionModel())->countAllResults();
        $branches       = (new BranchModel())->where('status', 'active')->countAllResults();
        $departments    = (new DepartmentModel())->where('status', 'active')->countAllResults();
        $sessions       = $this->countActiveSessions();

        $activePct = $totalUsers > 0 ? round(($activeUsers / $totalUsers) * 100, 1) : 0;

        return [
            [
                'label'     => 'TOTAL USERS',
                'icon'      => 'fa-users',
                'value'     => number_format($totalUsers),
                'badge'     => $newThisMonth > 0 ? '+' . $newThisMonth . ' this month' : 'no new users',
                'badgeType' => $newThisMonth > 0 ? 'positive' : 'positive',
                'dept'      => 'USERS',
            ],
            [
                'label'     => 'ACTIVE USERS',
                'icon'      => 'fa-user-check',
                'value'     => number_format($activeUsers),
                'badge'     => $activePct . '% of total',
                'badgeType' => 'positive',
                'dept'      => 'USERS',
            ],
            [
                'label'     => 'INACTIVE USERS',
                'icon'      => 'fa-user-slash',
                'value'     => number_format($inactiveUsers),
                'badge'     => $inactiveUsers > 0 ? 'needs review' : 'all clear',
                'badgeType' => $inactiveUsers > 0 ? 'negative' : 'positive',
                'dept'      => 'USERS',
            ],
            [
                'label'     => 'LOCKED ACCOUNTS',
                'icon'      => 'fa-lock',
                'value'     => number_format($lockedUsers),
                'badge'     => $lockedUsers > 0 ? 'action required' : 'none locked',
                'badgeType' => $lockedUsers > 0 ? 'negative' : 'positive',
                'dept'      => 'SECURITY',
            ],
            [
                'label'     => 'ROLES',
                'icon'      => 'fa-user-shield',
                'value'     => number_format($rolesCount),
                'badge'     => number_format($permissions) . ' permissions',
                'badgeType' => 'positive',
                'dept'      => 'ACCESS',
            ],
            [
                'label'     => 'BRANCHES',
                'icon'      => 'fa-code-branch',
                'value'     => number_format($branches),
                'badge'     => number_format($departments) . ' departments',
                'badgeType' => 'positive',
                'dept'      => 'ORG',
            ],
            [
                'label'     => 'ACTIVITY (24H)',
                'icon'      => 'fa-clock-rotate-left',
                'value'     => number_format(
                    (new ActivityLogModel())
                        ->where('created_at >=', date('Y-m-d H:i:s', strtotime('-24 hours')))
                        ->countAllResults()
                ),
                'badge'     => $this->successfulLoginsToday() . ' logins today',
                'badgeType' => 'positive',
                'dept'      => 'SYSTEM',
            ],
            [
                'label'     => 'ACTIVE SESSIONS',
                'icon'      => 'fa-display',
                'value'     => number_format($sessions),
                'badge'     => $sessions === 1 ? '1 device online' : $sessions . ' devices online',
                'badgeType' => 'positive',
                'dept'      => 'AUTH',
            ],
        ];
    }

    public function chartData(): array
    {
        $year = (int) date('Y');

        return [
            'q1' => $this->periodCharts($year, 1),
            'q2' => $this->periodCharts($year, 2),
            'q3' => $this->periodCharts($year, 3),
            'q4' => $this->periodCharts($year, 4),
            'fy' => $this->fiscalYearCharts($year),
        ];
    }

    public function defaultChartPeriod(): string
    {
        return 'q' . (int) ceil((int) date('n') / 3);
    }

    private function periodCharts(int $year, int $quarter): array
    {
        $months = $this->quarterMonths($year, $quarter);

        return [
            'registrations' => [
                'labels' => array_column($months, 'label'),
                'values' => array_map(function ($m) {
                    return $this->countUsersCreatedBetween($m['start'], $m['end']);
                }, $months),
            ],
            'usersByRole' => $this->usersGroupedBy('roles', 'role_id', 'name'),
            'usersByBranch' => $this->usersByBranch(),
            'loginActivity' => [
                'labels' => array_column($months, 'label'),
                'values' => array_map(function ($m) {
                    return $this->countSuccessfulLoginsBetween($m['start'], $m['end']);
                }, $months),
            ],
        ];
    }

    private function fiscalYearCharts(int $year): array
    {
        $quarters = [];
        for ($q = 1; $q <= 4; $q++) {
            $months    = $this->quarterMonths($year, $q);
            $start     = $months[0]['start'];
            $end       = $months[2]['end'];
            $quarters[] = [
                'label' => 'Q' . $q,
                'start' => $start,
                'end'   => $end,
            ];
        }

        return [
            'registrations' => [
                'labels' => array_column($quarters, 'label'),
                'values' => array_map(function ($q) {
                    return $this->countUsersCreatedBetween($q['start'], $q['end']);
                }, $quarters),
            ],
            'usersByRole' => $this->usersGroupedBy('roles', 'role_id', 'name'),
            'usersByBranch' => $this->usersByBranch(),
            'loginActivity' => [
                'labels' => array_column($quarters, 'label'),
                'values' => array_map(function ($q) {
                    return $this->countSuccessfulLoginsBetween($q['start'], $q['end']);
                }, $quarters),
            ],
        ];
    }

    /**
     * @return list<array{label: string, start: string, end: string}>
     */
    private function quarterMonths(int $year, int $quarter): array
    {
        $startMonth = ($quarter - 1) * 3 + 1;
        $months     = [];

        for ($i = 0; $i < 3; $i++) {
            $monthNum = $startMonth + $i;
            $start    = sprintf('%04d-%02d-01 00:00:00', $year, $monthNum);
            $end      = date('Y-m-d H:i:s', strtotime($start . ' +1 month'));

            $months[] = [
                'label' => date('M', strtotime($start)),
                'start' => $start,
                'end'   => $end,
            ];
        }

        return $months;
    }

    private function countUsers(array $where = []): int
    {
        $builder = $this->db->table('users')->where('deleted_at', null);
        foreach ($where as $field => $value) {
            $builder->where($field, $value);
        }

        return $builder->countAllResults();
    }

    private function countUsersCreatedSince(string $since): int
    {
        return $this->db->table('users')
            ->where('deleted_at', null)
            ->where('created_at >=', $since)
            ->countAllResults();
    }

    private function countUsersCreatedBetween(string $start, string $end): int
    {
        return $this->db->table('users')
            ->where('deleted_at', null)
            ->where('created_at >=', $start)
            ->where('created_at <', $end)
            ->countAllResults();
    }

    private function countSuccessfulLoginsBetween(string $start, string $end): int
    {
        return $this->db->table('login_attempts')
            ->where('was_successful', 1)
            ->where('created_at >=', $start)
            ->where('created_at <', $end)
            ->countAllResults();
    }

    private function successfulLoginsToday(): int
    {
        return $this->countSuccessfulLoginsBetween(
            date('Y-m-d 00:00:00'),
            date('Y-m-d 00:00:00', strtotime('+1 day'))
        );
    }

    private function countActiveSessions(): int
    {
        return (new UserSessionModel())->where('revoked_at', null)->countAllResults();
    }

    private function usersGroupedBy(string $table, string $foreignKey, string $labelColumn): array
    {
        $rows = $this->db->table($table . ' t')
            ->select("t.{$labelColumn} AS label, COUNT(u.id) AS total", false)
            ->join('users u', "u.{$foreignKey} = t.id AND u.deleted_at IS NULL", 'left', false)
            ->groupBy('t.id, t.' . $labelColumn)
            ->orderBy('total', 'DESC')
            ->get()
            ->getResultArray();

        if ($rows === []) {
            return ['labels' => ['No roles'], 'values' => [0]];
        }

        return [
            'labels' => array_map(function ($r) {
                return $r['label'] ?? 'Unknown';
            }, $rows),
            'values' => array_map(function ($r) {
                return (int) $r['total'];
            }, $rows),
        ];
    }

    private function usersByBranch(): array
    {
        $rows = $this->db->query("
            SELECT COALESCE(b.name, 'Unassigned') AS label, COUNT(u.id) AS total
            FROM users u
            LEFT JOIN branches b ON b.id = u.branch_id
            WHERE u.deleted_at IS NULL
            GROUP BY b.id, b.name
            ORDER BY total DESC
        ")->getResultArray();

        if ($rows === []) {
            return ['labels' => ['Unassigned'], 'values' => [0]];
        }

        return [
            'labels' => array_map(function ($r) {
                return $r['label'];
            }, $rows),
            'values' => array_map(function ($r) {
                return (int) $r['total'];
            }, $rows),
        ];
    }
}
