<?php
declare(strict_types=1);

namespace App\Http;

use App\Support\Translator;
use App\Support\FileLogger;
use Throwable;

final class ApiRouter
{
    public function __construct(
        private readonly ?QuestionApiController $questions = null,
        private readonly string $locale = 'ar',
        private readonly ?Translator $translator = null,
        private readonly ?ApiMutationController $mutations = null,
        private readonly bool $schemaReady = true,
        private readonly string $fallbackLocale = 'ar',
    ) {}

    public function dispatch(string $method, string $path, array $query = [], array $input = []): JsonResponse
    {
        $route=$this->routePath($path);if($route===null)return JsonResponse::failure(404,'route_not_found',$this->message('route_not_found'));
        $method=strtoupper(trim($method));
        $schemaMutation = $method === 'POST' && (
            $route === '/questions' || $route === '/reports' || $route === '/votes' || $route === '/follows'
            || preg_match('~^/(?:questions|answers)/\d+/(?:answers|comments|accept)$~', $route) === 1
        );
        if ($schemaMutation && !$this->schemaReady) {
            return JsonResponse::failure(503, 'database_upgrade_required', $this->message('database_upgrade_required'));
        }
        try {
            if($route==='/questions'){
                if($method==='GET')return $this->questions?->listQuestions($query) ?? JsonResponse::failure(503,'database_unavailable',$this->message('database_unavailable'));
                if($method==='POST')return $this->mutations?->createQuestion($input) ?? $this->notImplemented($route,$method);
                return $this->methodNotAllowed(['GET','POST']);
            }
            if(preg_match('~^/questions/([^/]+)$~',$route,$m)===1){
                if($method!=='GET')return $this->methodNotAllowed(['GET']);
                return $this->questions?->showQuestion(rawurldecode($m[1]), $query) ?? JsonResponse::failure(503,'database_unavailable',$this->message('database_unavailable'));
            }
            if($route==='/notifications'){
                if($method!=='GET')return $this->methodNotAllowed(['GET']);
                return $this->mutations?->notifications() ?? $this->notImplemented($route,$method);
            }
            if($route==='/me'){
                if($method!=='GET')return $this->methodNotAllowed(['GET']);
                return $this->mutations?->me() ?? $this->notImplemented($route,$method);
            }
            if($route==='/reports'){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->createReport($input) ?? $this->notImplemented($route,$method);
            }
            if($route==='/votes'){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->castVote($input) ?? $this->notImplemented($route,$method);
            }
            if($route==='/follows'){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->toggleFollow($input) ?? $this->notImplemented($route,$method);
            }
            if(preg_match('~^/questions/(\d+)/answers$~',$route,$m)===1){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->createAnswer((int)$m[1],$input) ?? $this->notImplemented($route,$method);
            }
            if(preg_match('~^/questions/(\d+)/comments$~',$route,$m)===1){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->createComment('question',(int)$m[1],$input) ?? $this->notImplemented($route,$method);
            }
            if(preg_match('~^/answers/(\d+)/comments$~',$route,$m)===1){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->createComment('answer',(int)$m[1],$input) ?? $this->notImplemented($route,$method);
            }
            if(preg_match('~^/answers/(\d+)/accept$~',$route,$m)===1){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->mutations?->acceptAnswer((int)$m[1]) ?? $this->notImplemented($route,$method);
            }
            if(preg_match('~^/questions/(\d+)/accept$~',$route,$m)===1){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                $answerId=(int)($input['answer_id']??0);
                return $answerId>0 ? ($this->mutations?->acceptAnswer($answerId) ?? $this->notImplemented($route,$method)) : JsonResponse::failure(422,'invalid_request',$this->message('mutation_failed'));
            }

            // Reserved auth/report mutation routes remain explicit until their API contracts are finalized.
            if(in_array($route,['/comments','/auth/register','/auth/login','/auth/revoke','/auth/forgot-password','/auth/reset-password','/auth/verify-email'],true)){
                if($method!=='POST')return $this->methodNotAllowed(['POST']);
                return $this->notImplemented($route,$method);
            }
            return JsonResponse::failure(404,'route_not_found',$this->message('route_not_found'));
        } catch(Throwable $throwable) {
            (new FileLogger())->error('API request failed.', $throwable, ['route' => $route, 'method' => $method]);
            return JsonResponse::failure(500,'server_error',$this->message('server_error'));
        }
    }

    private function routePath(string $path): ?string
    {
        $parsed=parse_url($path,PHP_URL_PATH);if(!is_string($parsed))return null;$marker='/api/v1';$position=strpos($parsed,$marker);if($position===false)return null;
        $afterPosition=$position+strlen($marker);$after=$parsed[$afterPosition]??'';if(($position>0&&$parsed[$position-1]==='/')||($after!==''&&$after!=='/'))return null;
        $route=substr($parsed,$afterPosition);return '/'.trim($route,'/');
    }

    private function methodNotAllowed(array $allow): JsonResponse
    {
        return JsonResponse::failure(405,'method_not_allowed',$this->message('method_not_allowed'),['allow'=>$allow]);
    }

    private function notImplemented(string $route,string $method): JsonResponse
    {
        return JsonResponse::failure(501,'not_implemented',$this->message('not_implemented'),['route'=>$route,'method'=>$method]);
    }

    private function message(string $key): string
    {
        $translator = $this->translator ?? new Translator($this->locale, $this->fallbackLocale);
        return $translator->get('api.' . $key);
    }
}
