<?php

namespace App\Http\Controllers\Admin;

use App\Http\Resources\AdminInstance;
use App\Http\Resources\AdminProfile;
use App\Instance;
use App\Profile;
use App\Services\InstanceService;
use Cache;
use Illuminate\Http\Request;
use Illuminate\Validation\Rule;

trait AdminInstanceController
{
    public function instances(Request $request)
    {
        return view('admin.instances.home');
    }

    public function instanceScan(Request $request)
    {
        Profile::whereNotNull('domain')
            ->latest()
            ->groupBy(['domain', 'id'])
            ->where('created_at', '>', now()->subMonths(2))
            ->chunk(100, function ($domains) {
                foreach ($domains as $domain) {
                    Instance::firstOrCreate([
                        'domain' => $domain->domain,
                    ]);
                }
            });

        return redirect()->back();
    }

    public function instanceShow(Request $request, $id)
    {
        $instance = Instance::findOrFail($id);

        return view('admin.instances.show', compact('instance'));
    }

    public function instanceEdit(Request $request, $id)
    {
        $this->validate($request, [
            'action' => [
                'required',
                'string',
                'min:1',
                'max:20',
                Rule::in(['autocw', 'unlist', 'ban']),
            ],
        ]);

        $instance = Instance::findOrFail($id);
        $unlisted = $instance->unlisted;
        $autocw = $instance->auto_cw;
        $banned = $instance->banned;

        switch ($request->action) {
            case 'autocw':
                $instance->auto_cw = $autocw == true ? false : true;
                $instance->save();
                break;

            case 'unlist':
                $instance->unlisted = $unlisted == true ? false : true;
                $instance->save();
                break;

            case 'ban':
                $instance->banned = $banned == true ? false : true;
                $instance->save();
                break;
        }

        Cache::forget(InstanceService::CACHE_KEY_BANNED_DOMAINS);
        Cache::forget(InstanceService::CACHE_KEY_UNLISTED_DOMAINS);
        Cache::forget(InstanceService::CACHE_KEY_NSFW_DOMAINS);

        return response()->json([]);
    }

    public function getInstancesStatsApi(Request $request)
    {
        return InstanceService::stats();
    }

    public function getInstancesQueryApi(Request $request)
    {
        $this->validate($request, [
            'q' => 'required',
        ]);

        $q = $request->input('q');

        return AdminInstance::collection(
            Instance::where('domain', 'like', '%'.$q.'%')
                ->orderByDesc('user_count')
                ->cursorPaginate(10)
                ->withQueryString()
        );
    }

    public function getInstancesApi(Request $request)
    {
        $this->validate($request, [
            'filter' => [
                'nullable',
                'string',
                'min:1',
                'max:20',
                Rule::in([
                    'cw',
                    'unlisted',
                    'banned',
                    'popular_users',
                    'popular_statuses',
                    'new',
                    'all',
                ]),
            ],
            'sort' => [
                'sometimes',
                'string',
                Rule::in([
                    'id',
                    'domain',
                    'software',
                    'user_count',
                    'status_count',
                    'banned',
                    'auto_cw',
                    'unlisted',
                ]),
            ],
            'dir' => 'sometimes|in:desc,asc',
        ]);
        $filter = $request->input('filter');
        $query = $request->input('q');
        $sortCol = $request->input('sort');
        $sortDir = $request->input('dir');

        return AdminInstance::collection(Instance::when($query, function ($q, $qq) use ($query) {
            return $q->where('domain', 'like', '%'.$query.'%');
        })
            ->when($filter, function ($q, $f) use ($filter) {
                if ($filter == 'cw') {
                    return $q->whereAutoCw(true);
                }
                if ($filter == 'unlisted') {
                    return $q->whereUnlisted(true);
                }
                if ($filter == 'banned') {
                    return $q->whereBanned(true);
                }
                if ($filter == 'new') {
                    return $q->orderByDesc('id');
                }
                if ($filter == 'popular_users') {
                    return $q->orderByDesc('user_count');
                }
                if ($filter == 'popular_statuses') {
                    return $q->orderByDesc('status_count');
                }

                return $q->orderByDesc('id');
            })
            ->when($sortCol, function ($q, $s) use ($sortCol, $sortDir, $filter) {
                if (! in_array($filter, ['popular_users', 'popular_statuses'])) {
                    return $q->whereNotNull($sortCol)->orderBy($sortCol, $sortDir);
                }
            }, function ($q) use ($filter) {
                if (! $filter || ! in_array($filter, ['popular_users', 'popular_statuses'])) {
                    return $q->orderByDesc('id');
                }
            })
            ->cursorPaginate(10)
            ->withQueryString());
    }

    public function postInstanceUpdateApi(Request $request)
    {
        $this->validate($request, [
            'id' => 'required',
            'banned' => 'boolean',
            'auto_cw' => 'boolean',
            'unlisted' => 'boolean',
            'notes' => 'nullable|string|max:500',
        ]);

        $id = $request->input('id');
        $instance = Instance::findOrFail($id);
        $instance->update($request->only([
            'banned',
            'auto_cw',
            'unlisted',
            'notes',
        ]));

        InstanceService::refresh();

        return new AdminInstance($instance);
    }

    public function postInstanceCreateNewApi(Request $request)
    {
        $this->validate($request, [
            'domain' => 'required|string',
            'banned' => 'boolean',
            'auto_cw' => 'boolean',
            'unlisted' => 'boolean',
            'notes' => 'nullable|string|max:500',
        ]);

        $domain = $request->input('domain');

        abort_if(! strpos($domain, '.'), 400, 'Invalid domain');
        abort_if(! filter_var($domain, FILTER_VALIDATE_DOMAIN), 400, 'Invalid domain');

        $instance = new Instance;
        $instance->domain = $request->input('domain');
        $instance->banned = $request->input('banned');
        $instance->auto_cw = $request->input('auto_cw');
        $instance->unlisted = $request->input('unlisted');
        $instance->manually_added = true;
        $instance->notes = $request->input('notes');
        $instance->save();

        InstanceService::refresh();

        return new AdminInstance($instance);
    }

    public function postInstanceRefreshStatsApi(Request $request)
    {
        $this->validate($request, [
            'id' => 'required',
        ]);

        $instance = Instance::findOrFail($request->input('id'));
        $instance->user_count = Profile::whereDomain($instance->domain)->count();
        $instance->status_count = Profile::whereDomain($instance->domain)->leftJoin('statuses', 'profiles.id', '=', 'statuses.profile_id')->count();
        $instance->save();

        return new AdminInstance($instance);
    }

    public function postInstanceDeleteApi(Request $request)
    {
        $this->validate($request, [
            'id' => 'required',
        ]);

        $instance = Instance::findOrFail($request->input('id'));
        $instance->delete();

        InstanceService::refresh();

        return 200;
    }

    public function downloadBackup(Request $request)
    {
        return response()->streamDownload(function () {
            $json = [
                'version' => 1,
                'auto_cw' => Instance::whereAutoCw(true)->pluck('domain')->toArray(),
                'unlisted' => Instance::whereUnlisted(true)->pluck('domain')->toArray(),
                'banned' => Instance::whereBanned(true)->pluck('domain')->toArray(),
                'created_at' => now()->format('c'),
            ];
            $chk = hash('sha256', json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
            $json['_sha256'] = $chk;
            echo json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
        }, 'pixelfed-instances-mod.json');
    }

    public function importBackup(Request $request)
    {
        $this->validate($request, [
            'banned' => 'sometimes|array',
            'auto_cw' => 'sometimes|array',
            'unlisted' => 'sometimes|array',
        ]);

        $banned = $request->input('banned');
        $auto_cw = $request->input('auto_cw');
        $unlisted = $request->input('unlisted');

        foreach ($banned as $i) {
            Instance::updateOrCreate(
                ['domain' => $i],
                ['banned' => true]
            );
        }

        foreach ($auto_cw as $i) {
            Instance::updateOrCreate(
                ['domain' => $i],
                ['auto_cw' => true]
            );
        }

        foreach ($unlisted as $i) {
            Instance::updateOrCreate(
                ['domain' => $i],
                ['unlisted' => true]
            );
        }

        InstanceService::refresh();

        return [200];
    }

    // public function getInstanceAccounts(Request $request, $id)
    // {
    //     $instance = Instance::findOrFail($id);
    //     $res = Profile::whereDomain($instance->domain)->cursorPaginate(10);
    //     return AdminProfile::collection($res);
    // }
}
