<?php
namespace boru\boruai\Models;

class ToolParameters {
    private $type = "object";
    private $properties = [];
    private $additionalProperties = false;

    private $rawJson = null;

    public function __construct($input=[],$isRaw=false) {
        if($isRaw) {
            if(is_array($input)) {
                $this->rawJson = json_encode($input,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE);
            } else {
                $this->rawJson = $input;
            }
            return;
        }
        if(!is_array($input)) {
            return;
        }
        $nameArr = false;
        if(isset($input["type"])) {
            $nameArr = true;
            $this->type = $input["type"];
        }
        if(isset($input["properties"])) {
            $nameArr = true;
            foreach($input["properties"] as $name => $property) {
                if($property instanceof ToolProperty) {
                    $this->properties[$property->name()] = $property;
                } else {
                    $this->properties[$name] = new ToolProperty($property);
                    if($this->properties[$name]->name() != $name) {
                        $this->properties[$name]->name($name);
                    }
                }
            }
        }
        if(!$nameArr) {
            foreach($input as $name => $property) {
                if($property instanceof ToolProperty) {
                    $this->properties[$property->name()] = $property;
                } else {
                    $this->properties[$name] = new ToolProperty($property);
                    if($this->properties[$name]->name() != $name) {
                        $this->properties[$name]->name($name);
                    }
                }
            }
        }
    }

    public function type($type=null) {
        if($type !== null) {
            $this->type = $type;
            return $this;
        }
        return $this->type;
    }

    public function properties($properties=null) {
        if($properties !== null) {
            $this->properties = $properties;
            return $this;
        }
        return $this->properties;
    }

    public function additionalProperties($value = null) {
        if ($value !== null) {
            $this->additionalProperties = $value ? true : false;
            return $this;
        }
        return $this->additionalProperties;
    }

    public function compile($strict=true) {
        if($this->rawJson) {
            return json_decode($this->rawJson, true);
        }
        $compiled = [
            "type" => $this->type,
            "properties" => [],
            "additionalProperties" => $this->additionalProperties
        ];
        $required = [];
        foreach($this->properties as $property) {
            $compiled["properties"][$property->name()] = $property->compile();
            if($property->required() || $strict) {
                $required[] = $property->name();
            }
        }
        if(count($required) > 0) {
            $compiled["required"] = $required;
        }
        if($strict) {
            $compiled["additionalProperties"] = false;
        }
        return $compiled;
    }

    public function addProperty($property) {
        if ($property instanceof ToolProperty) {
            $this->properties[$property->name()] = $property;
        } else {
            // Allow raw arrays or simple definitions
            $tp = new ToolProperty($property);
            $this->properties[$tp->name()] = $tp;
        }
        return $this;
    }

    // Convenience helpers (optional)
    public function addString($name, $description, $enum = [], $required = true) {
        $p = new ToolProperty([
            "name"        => $name,
            "type"        => "string",
            "description" => $description,
            "required"    => $required,
            "enum"        => $enum,
        ]);
        return $this->addProperty($p);
    }

    public function addInteger($name, $description, $enum = [], $required = true) {
        $p = new ToolProperty([
            "name"        => $name,
            "type"        => "integer",
            "description" => $description,
            "required"    => $required,
            "enum"        => $enum,
        ]);
        return $this->addProperty($p);
    }

    public function addNumber($name, $description, $required = true) {
        $p = new ToolProperty([
            "name"        => $name,
            "type"        => "number",
            "description" => $description,
            "required"    => $required,
        ]);
        return $this->addProperty($p);
    }

    public function addBool($name, $description, $required = true) {
        $p = new ToolProperty([
            "name"        => $name,
            "type"        => "boolean",
            "description" => $description,
            "required"    => $required,
        ]);
        return $this->addProperty($p);
    }

    public function addObject($name, $description = null, $required = true, array $subProps = []) {
        // $subProps can be:
        //   - array of ToolProperty / arrays
        //   - ToolParameters instance (we’ll extract its properties)

        $propertiesArray = [];

        if ($subProps instanceof ToolParameters) {
            // reuse its properties directly
            $propertiesArray = $subProps->properties();
        } elseif (is_array($subProps)) {
            foreach ($subProps as $key => $prop) {
                if ($prop instanceof ToolProperty) {
                    $propertiesArray[$prop->name()] = $prop;
                } else {
                    // $key can be name; if not set in $prop, we'll apply it in ToolProperty ctor
                    if (is_string($key) && is_array($prop) && !isset($prop['name'])) {
                        $prop['name'] = $key;
                    }
                    $tp = new ToolProperty($prop);
                    $propertiesArray[$tp->name()] = $tp;
                }
            }
        }

        $p = new ToolProperty([
            "name"        => $name,
            "type"        => "object",
            "description" => $description,
            "required"    => $required,
            "properties"  => $propertiesArray,
        ]);
        return $this->addProperty($p);
    }

    public function addAnyOf($name, array $options = []) {
        // $options should be ToolProperty[] or raw arrays.
        $props = [];
        foreach ($options as $opt) {
            if ($opt instanceof ToolProperty) {
                $props[$opt->name()] = $opt;
            } else {
                $tp = new ToolProperty($opt);
                $props[$tp->name()] = $tp;
            }
        }

        $p = new ToolProperty([
            "name"       => $name,
            "type"       => "anyOf",
            "properties" => $props,
            "required"   => true,
        ]);
        return $this->addProperty($p);
    }
}