<?php
namespace EasyChat\Controller;

use EasyChat\Library\Ai\LeadSearchPlanAssistant;
use EasyChat\Library\RequestContext;

class LeadPlanner extends Base {
    protected $layouts = '';
    public function index() { return $this->reply(404,['error'=>'not_found']); }
    public function generate() {
        header('Content-Type: application/json; charset=utf-8');header('Cache-Control: no-store');
        if (strtoupper((string)(RequestContext::server()['REQUEST_METHOD'] ?? 'GET')) !== 'POST') return $this->reply(405,['error'=>'method_not_allowed']);
        try {$this->authorize();$raw=file_get_contents('php://input');if(!is_string($raw)||strlen($raw)>65536)throw new \InvalidArgumentException('payload_too_large');$input=json_decode($raw,true,32,JSON_THROW_ON_ERROR);if(!is_array($input)||($input['version']??'')!=='1.0')throw new \InvalidArgumentException('invalid_contract');$result=(new LeadSearchPlanAssistant($this->registry))->generate($input);$this->reply(200,$result);} catch (\UnexpectedValueException $e) {$this->reply(401,['error'=>'unauthorized']);} catch (\InvalidArgumentException|\JsonException $e) {$this->reply(422,['error'=>'invalid_request']);} catch (\RuntimeException $e) {$this->reply(503,['error'=>'planner_unavailable']);}
    }
    private function authorize() {
        $secret=defined('EASYCHAT_LEAD_PLANNER_JWT_SECRET')?(string)constant('EASYCHAT_LEAD_PLANNER_JWT_SECRET'):'';if(strlen($secret)<32)throw new \RuntimeException('planner_not_configured');$authorization=(string)(RequestContext::server()['HTTP_AUTHORIZATION']??'');if(strpos($authorization,'Bearer ')!==0)throw new \UnexpectedValueException('unauthorized');$parts=explode('.',substr($authorization,7));if(count($parts)!==3)throw new \UnexpectedValueException('unauthorized');$jwtHeader=json_decode($this->decode($parts[0]),true);if(!is_array($jwtHeader)||($jwtHeader['alg']??'')!=='HS256'||(($jwtHeader['typ']??'JWT')!=='JWT'))throw new \UnexpectedValueException('unauthorized');$expected=$this->b64(hash_hmac('sha256',$parts[0].'.'.$parts[1],$secret,true));if(!hash_equals($expected,$parts[2]))throw new \UnexpectedValueException('unauthorized');$claims=json_decode($this->decode($parts[1]),true);$now=time();$iat=(int)($claims['iat']??0);$exp=(int)($claims['exp']??0);if(!is_array($claims)||($claims['aud']??'')!=='easychat-ai'||($claims['scope']??'')!=='lead_plans:generate'||$iat<$now-30||$iat>$now+30||$exp<=$now||$exp>$now+90||$exp<=$iat||!preg_match('/^[a-f0-9]{32}$/',(string)($claims['jti']??'')))throw new \UnexpectedValueException('unauthorized');$this->claimJti($claims['jti'],$now);
    }
    private function claimJti($jti,$now){$path=DIR_LOGS.'/lead_planner_jti.json';$handle=fopen($path,'c+');if(!$handle||!flock($handle,LOCK_EX))throw new \RuntimeException('replay_store_unavailable');$raw=stream_get_contents($handle);$items=json_decode((string)$raw,true);if(!is_array($items))$items=[];foreach($items as$key=>$expires)if((int)$expires<$now)unset($items[$key]);if(isset($items[$jti])){flock($handle,LOCK_UN);fclose($handle);throw new \UnexpectedValueException('replay');}$items[$jti]=$now+120;ftruncate($handle,0);rewind($handle);$encoded=json_encode($items);if(!is_string($encoded)||fwrite($handle,$encoded)===false){flock($handle,LOCK_UN);fclose($handle);throw new \RuntimeException('replay_store_unavailable');}fflush($handle);flock($handle,LOCK_UN);fclose($handle);@chmod($path,0600);}
    private function decode($value){$pad=strlen($value)%4;return base64_decode(strtr($value.($pad?str_repeat('=',4-$pad):''),'-_','+/'),true);}private function b64($value){return rtrim(strtr(base64_encode($value),'+/','-_'),'=');}private function reply($status,array $data){http_response_code($status);echo json_encode($data,JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES);exit;}
}
