<?php
if (!function_exists('sitesmith_validate_response')) {
    function sitesmith_validate_response($obj): array {
        if (!is_array($obj))      return ['ok'=>false,'error'=>'response not object'];
        if (!isset($obj['type'])) return ['ok'=>false,'error'=>'missing type'];
        switch ($obj['type']) {
            case 'replace': return _sm_v_replace($obj);
            case 'patch':   return _sm_v_patch($obj);
            case 'ask':     return _sm_v_ask($obj);
            default:        return ['ok'=>false,'error'=>'unknown type: '.$obj['type']];
        }
    }
    function _sm_v_replace(array $o): array {
        if (!in_array(($o['scope']??null),['site','page','section'],true)) return ['ok'=>false,'error'=>'replace.scope must be site|page|section'];
        if (!isset($o['pages']) || !is_array($o['pages']) || count($o['pages'])===0) return ['ok'=>false,'error'=>'replace.pages required non-empty'];
        foreach ($o['pages'] as $i=>$p) {
            if (!is_array($p) || !is_string($p['name']??null) || !is_array($p['tree']??null)) return ['ok'=>false,'error'=>"replace.pages[$i] invalid"];
            $e = _sm_v_tree($p['tree'], "replace.pages[$i].tree"); if ($e) return ['ok'=>false,'error'=>$e];
        }
        foreach (['header','footer'] as $opt) if (isset($o[$opt])) {
            if (!is_array($o[$opt]) || !is_array($o[$opt]['tree']??null)) return ['ok'=>false,'error'=>"replace.$opt requires tree"];
            $e = _sm_v_tree($o[$opt]['tree'], "replace.$opt.tree"); if ($e) return ['ok'=>false,'error'=>$e];
        }
        if (!is_string($o['message']??'')) return ['ok'=>false,'error'=>'replace.message must be string'];
        return ['ok'=>true,'data'=>$o];
    }
    function _sm_v_patch(array $o): array {
        if (!isset($o['ops']) || !is_array($o['ops']) || count($o['ops'])===0) return ['ok'=>false,'error'=>'patch.ops required non-empty'];
        $valid = ['update_props','replace_node','insert_after','insert_before','delete_node'];
        foreach ($o['ops'] as $i=>$op) {
            if (!is_array($op)) return ['ok'=>false,'error'=>"patch.ops[$i] not object"];
            if (!in_array(($op['op']??null), $valid, true)) return ['ok'=>false,'error'=>"patch.ops[$i].op invalid"];
            if (!is_string($op['node_id']??null) || $op['node_id']==='') return ['ok'=>false,'error'=>"patch.ops[$i].node_id required"];
            switch ($op['op']) {
                case 'update_props':
                    if (!is_array($op['props']??null)) return ['ok'=>false,'error'=>"patch.ops[$i].props required"];
                    break;
                case 'replace_node':
                case 'insert_after':
                case 'insert_before':
                    if (!is_array($op['tree']??null)) return ['ok'=>false,'error'=>"patch.ops[$i].tree required"];
                    $e = _sm_v_tree($op['tree'], "patch.ops[$i].tree"); if ($e) return ['ok'=>false,'error'=>$e];
                    break;
                case 'delete_node': break;
            }
        }
        if (!is_string($o['message']??'')) return ['ok'=>false,'error'=>'patch.message must be string'];
        return ['ok'=>true,'data'=>$o];
    }
    function _sm_v_ask(array $o): array {
        if (!is_string($o['question']??null) || $o['question']==='') return ['ok'=>false,'error'=>'ask.question required'];
        if (isset($o['options']) && !is_array($o['options'])) return ['ok'=>false,'error'=>'ask.options array'];
        if (isset($o['options'])) foreach ($o['options'] as $i=>$v) if (!is_string($v)) return ['ok'=>false,'error'=>"ask.options[$i] string"];
        return ['ok'=>true,'data'=>$o];
    }
    function _sm_v_tree($node, string $path): ?string {
        if (!is_array($node)) return "$path not object";
        if (!is_string($node['type']['resolvedName']??null)) return "$path.type.resolvedName missing";
        if (!is_array($node['props']??null)) return "$path.props missing";
        if (isset($node['nodes'])) {
            if (!is_array($node['nodes'])) return "$path.nodes array";
            foreach ($node['nodes'] as $i=>$c) { $e = _sm_v_tree($c, "$path.nodes[$i]"); if ($e) return $e; }
        }
        return null;
    }
}
