<?php
namespace boru\ai\Config;

class Config
{
    /** @var array */
    protected $data = array();

    public function __construct(array $data = array())
    {
        $this->data = $data;
    }

    public function set($key, $value)
    {
        $segments = explode('.', (string)$key);
        $target = &$this->data;

        foreach ($segments as $segment) {
            if (!isset($target[$segment]) || !is_array($target[$segment])) {
                $target[$segment] = array();
            }
            $target = &$target[$segment];
        }

        $target = $value;
        return $this;
    }

    public function get($key = null, $default = null)
    {
        if ($key === null) {
            return $this->data;
        }

        $segments = explode('.', (string)$key);
        $target = $this->data;

        foreach ($segments as $segment) {
            if (!is_array($target) || !array_key_exists($segment, $target)) {
                return $default;
            }
            $target = $target[$segment];
        }

        return $target;
    }

    public function has($key)
    {
        return $this->get($key, '__boru_ai_missing__') !== '__boru_ai_missing__';
    }

    public function merge(array $data)
    {
        $this->data = $this->mergeRecursive($this->data, $data);
        return $this;
    }

    public function provider($name, array $data = null)
    {
        $key = 'providers.' . $name;
        if ($data !== null) {
            $existing = $this->get($key, array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set($key, $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get($key, array());
        return is_array($value) ? $value : array();
    }

    public function defaults(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('defaults', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('defaults', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('defaults', array());
        return is_array($value) ? $value : array();
    }

    public function runtime(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('runtime', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('runtime', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('runtime', array());
        return is_array($value) ? $value : array();
    }

    public function persistence(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('persistence', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('persistence', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('persistence', array());
        return is_array($value) ? $value : array();
    }

    public function db(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('db', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('db', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('db', array());
        return is_array($value) ? $value : array();
    }

    public function vector(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('vector', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('vector', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('vector', array());
        return is_array($value) ? $value : array();
    }

    public function mcp(array $data = null)
    {
        if ($data !== null) {
            $existing = $this->get('mcp', array());
            if (!is_array($existing)) {
                $existing = array();
            }
            $this->set('mcp', $this->mergeRecursive($existing, $data));
            return $this;
        }
        $value = $this->get('mcp', array());
        return is_array($value) ? $value : array();
    }

    public function toArray()
    {
        return $this->data;
    }

    protected function mergeRecursive(array $left, array $right)
    {
        foreach ($right as $key => $value) {
            if (isset($left[$key]) && is_array($left[$key]) && is_array($value)) {
                $left[$key] = $this->mergeRecursive($left[$key], $value);
            } else {
                $left[$key] = $value;
            }
        }
        return $left;
    }
}
