<?php

namespace App\Services;

use App\Avatar;
use App\Contact;
use App\FailedJob;
use App\Instance;
use App\Media;
use App\Profile;
use App\Report;
use App\Status;
use App\User;
use App\Util\Lexer\PrettyNumber;
use Cache;
use DateInterval;
use DatePeriod;
use DB;

class AdminStatsService
{
    public static function get()
    {
        return array_merge(
            self::recentData(),
            self::additionalData(),
            self::postsGraph()
        );
    }

    public static function summary()
    {
        return array_merge(
            self::recentData(),
            self::additionalDataSummary(),
        );
    }

    public static function storage()
    {
        return Cache::remember('admin:dashboard:storage:stats', 120000, function () {
            $res = [];

            $res['last_updated'] = str_replace('+00:00', 'Z', now()->format(DATE_RFC3339_EXTENDED));

            $avatars = Avatar::count();
            $avatarsLocal = Avatar::whereNull('cdn_url')->count();
            $res['avatar'] = [
                'count' => $avatars,
                'local_count' => $avatarsLocal,
                'cloud_count' => ($avatars - $avatarsLocal),
                'total_sum' => Avatar::sum('size'),
            ];

            $media = Media::count();
            $mediaSum = Media::sum('size');
            $mediaLocalSum = Media::whereNotNull('user_id')->sum('size');
            $mediaLocal = Media::whereNotNull('user_id')->count();
            $res['media'] = [
                'count' => $media,
                'local_count' => $mediaLocal,
                'cloud_count' => ($media - $mediaLocal),
                'total_sum' => $mediaSum,
                'local_sum' => $mediaLocalSum,
                'local_30d' => Media::whereNotNull('user_id')->where('created_at', '>', now()->subDays(30))->sum('size'),
                'cloud_30d' => Media::whereNull('user_id')->where('created_at', '>', now()->subDays(30))->sum('size'),
                'cloud_sum' => ($mediaSum - $mediaLocalSum),
                'avg_size' => Media::avg('size'),
                'avg_mime' => Media::groupBy('mime')->orderByRaw('COUNT(*) DESC')->first()->mime,
            ];

            return $res;
        });
    }

    protected static function recentData()
    {
        $day = config('database.default') == 'pgsql' ? 'DATE_PART(\'day\',' : 'day(';
        $ttl = now()->addMinutes(15);

        return Cache::remember('admin:dashboard:home:data:v0:15min', $ttl, function () {
            return [
                'contact' => PrettyNumber::convert(Contact::whereNull('read_at')->count()),
                'contact_monthly' => PrettyNumber::convert(Contact::whereNull('read_at')->where('created_at', '>', now()->subMonth())->count()),
                'reports' => PrettyNumber::convert(Report::whereNull('admin_seen')->count()),
                'reports_monthly' => PrettyNumber::convert(Report::whereNull('admin_seen')->where('created_at', '>', now()->subMonth())->count()),
            ];
        });
    }

    protected static function additionalData()
    {
        $day = config('database.default') == 'pgsql' ? 'DATE_PART(\'day\',' : 'day(';
        $ttl = now()->addHours(24);

        return Cache::remember('admin:dashboard:home:data:v0:24hr', $ttl, function () {
            return [
                'failedjobs' => PrettyNumber::convert(FailedJob::where('failed_at', '>=', \Carbon\Carbon::now()->subDay())->count()),
                'statuses' => PrettyNumber::convert(intval(StatusService::totalLocalStatuses())),
                'statuses_monthly' => PrettyNumber::convert(Status::where('created_at', '>', now()->subMonth())->count()),
                'profiles' => PrettyNumber::convert(Profile::count()),
                'users' => PrettyNumber::convert(User::count()),
                'users_monthly' => PrettyNumber::convert(User::where('created_at', '>', now()->subMonth())->count()),
                'instances' => PrettyNumber::convert(Instance::count()),
                'media' => PrettyNumber::convert(Media::count()),
                'storage' => Media::sum('size'),
            ];
        });
    }

    protected static function additionalDataSummary()
    {
        $ttl = now()->addHours(24);

        return Cache::remember('admin:dashboard:home:data-summary:v0:24hr', $ttl, function () {
            return [
                'statuses' => PrettyNumber::convert(intval(StatusService::totalLocalStatuses())),
                'profiles' => PrettyNumber::convert(Profile::count()),
                'users' => PrettyNumber::convert(User::count()),
                'instances' => PrettyNumber::convert(Instance::count()),
            ];
        });
    }

    protected static function postsGraph()
    {
        $ttl = now()->addHours(12);

        return Cache::remember('admin:dashboard:home:data-postsGraph:v0.1:24hr', $ttl, function () {
            $gb = config('database.default') == 'pgsql' ? ['statuses.id', 'created_at'] : DB::raw('Date(created_at)');
            $s = Status::selectRaw('Date(created_at) as date, count(statuses.id) as count')
                ->where('created_at', '>=', now()->subWeek())
                ->groupBy($gb)
                ->orderBy('created_at', 'DESC')
                ->pluck('count', 'date');

            $begin = now()->subWeek();
            $end = now();
            $interval = new DateInterval('P1D');
            $daterange = new DatePeriod($begin, $interval, $end);
            $dates = [];
            foreach ($daterange as $date) {
                $dates[$date->format('Y-m-d')] = 0;
            }

            $dates = collect($dates)->merge($s);

            $s = Status::selectRaw('Date(created_at) as date, count(statuses.id) as count')
                ->where('created_at', '>=', now()->subWeeks(2))
                ->where('created_at', '<=', now()->subWeeks(1))
                ->groupBy($gb)
                ->orderBy('created_at', 'DESC')
                ->pluck('count', 'date');

            $begin = now()->subWeeks(2);
            $end = now()->subWeeks(1);
            $interval = new DateInterval('P1D');
            $daterange = new DatePeriod($begin, $interval, $end);
            $lw = [];
            foreach ($daterange as $date) {
                $lw[$date->format('Y-m-d')] = 0;
            }

            $lw = collect($lw)->merge($s);

            return [
                'posts_this_week' => $dates->values(),
                'posts_last_week' => $lw->values(),
            ];
        });
    }
}