<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\Admin;

use App\Http\Controllers\Controller;
use App\Models\User;
use App\Support\UsernamePolicy;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Symfony\Component\HttpFoundation\Response;

final class UsernameApprovalController extends Controller
{
    public function pending(): JsonResponse
    {
        $rows = DB::table('username_approval_requests')
            ->where('status', 'pending')
            ->orderBy('created_at')
            ->get([
                'id',
                'user_id',
                'requested_username',
                'context',
                'similar_to',
                'payload',
                'created_at',
            ]);

        return response()->json(['data' => $rows], Response::HTTP_OK);
    }

    public function approve(int $id, Request $request): JsonResponse
    {
        $row = DB::table('username_approval_requests')->where('id', $id)->first();
        if (! $row) {
            return response()->json(['message' => 'Request not found.'], Response::HTTP_NOT_FOUND);
        }

        if ((string) $row->status !== 'pending') {
            return response()->json(['message' => 'Request is not pending.'], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        DB::beginTransaction();
        try {
            DB::table('username_approval_requests')
                ->where('id', $id)
                ->update([
                    'status' => 'approved',
                    'reviewed_by' => (int) $request->user()->id,
                    'reviewed_at' => now(),
                    'review_note' => (string) $request->input('note', ''),
                    'updated_at' => now(),
                ]);

            if ((string) $row->context === 'profile_update' && ! empty($row->user_id)) {
                $this->applyProfileRename((int) $row->user_id, (string) $row->requested_username);
            }

            DB::commit();
        } catch (\Throwable $e) {
            DB::rollBack();
            return response()->json(['message' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
        }

        return response()->json([
            'success' => true,
            'id' => $id,
            'status' => 'approved',
        ], Response::HTTP_OK);
    }

    public function reject(int $id, Request $request): JsonResponse
    {
        $affected = DB::table('username_approval_requests')
            ->where('id', $id)
            ->where('status', 'pending')
            ->update([
                'status' => 'rejected',
                'reviewed_by' => (int) $request->user()->id,
                'reviewed_at' => now(),
                'review_note' => (string) $request->input('note', ''),
                'updated_at' => now(),
            ]);

        if ($affected === 0) {
            return response()->json(['message' => 'Request not found or not pending.'], Response::HTTP_NOT_FOUND);
        }

        return response()->json([
            'success' => true,
            'id' => $id,
            'status' => 'rejected',
        ], Response::HTTP_OK);
    }

    private function applyProfileRename(int $userId, string $requestedUsername): void
    {
        $user = User::query()->find($userId);
        if (! $user) {
            return;
        }

        $requested = UsernamePolicy::normalize($requestedUsername);
        if ($requested === '') {
            throw new \RuntimeException('Requested username is invalid.');
        }

        $exists = User::query()
            ->whereRaw('LOWER(username) = ?', [$requested])
            ->where('id', '!=', $userId)
            ->exists();

        if ($exists) {
            throw new \RuntimeException('Requested username is already taken.');
        }

        $old = UsernamePolicy::normalize((string) ($user->username ?? ''));
        if ($old === $requested) {
            return;
        }

        $user->username = $requested;
        $user->username_changed_at = now();
        if (Schema::hasColumn('users', 'last_username_change_at')) {
            $user->last_username_change_at = now();
        }
        $user->save();

        if ($old !== '') {
            DB::table('username_history')->insert([
                'user_id' => $userId,
                'old_username' => $old,
                'changed_at' => now(),
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            DB::table('username_redirects')->updateOrInsert(
                ['old_username' => $old],
                [
                    'new_username' => $requested,
                    'user_id' => $userId,
                    'created_at' => now(),
                    'updated_at' => now(),
                ]
            );
        }
    }
}
