<?php
namespace boru\ai\Tests\Asset;

use boru\ai\Asset\Asset;
use boru\ai\Asset\AssetBindingPolicy;
use boru\ai\Asset\AssetProviderInterface;
use boru\ai\Asset\AssetResolver;
use boru\ai\Asset\NullAssetStore;
use boru\ai\Asset\ProviderAssetBinding;
use boru\ai\Config\Config;
use PHPUnit\Framework\TestCase;

class AssetBindingPolicyTest extends TestCase
{
    protected function tearDown(): void
    {
        putenv('AI_ASSET_BINDINGS_REUSE');
        putenv('OPENAI_ASSET_BINDINGS_REUSE');
        putenv('AI_ASSET_BINDINGS_MAX_AGE_SECONDS');
        putenv('OPENAI_ASSET_BINDINGS_MAX_AGE_SECONDS');
    }

    public function testPolicyMergesPersistenceDefaultsWithProviderOverrides()
    {
        $config = new Config();
        $config->persistence(array(
            'asset_bindings' => array(
                'reuse' => true,
                'max_age_seconds' => 86400,
                'delete_remote_on_cleanup' => false,
                'track_last_used_at' => true,
            ),
        ));
        $config->provider('openai', array(
            'asset_bindings' => array(
                'max_age_seconds' => 3600,
                'delete_remote_on_cleanup' => true,
            ),
        ));

        $policy = AssetBindingPolicy::fromConfig($config, 'openai');

        $this->assertTrue($policy->reuse());
        $this->assertSame(3600, $policy->maxAgeSeconds());
        $this->assertTrue($policy->deleteRemoteOnCleanup());
        $this->assertTrue($policy->trackLastUsedAt());
    }

    public function testProviderEnvOverrideWinsForAssetBindingPolicy()
    {
        $config = new Config();
        $config->persistence(array(
            'asset_bindings' => array(
                'reuse' => true,
                'max_age_seconds' => 86400,
            ),
        ));
        $config->provider('openai', array(
            'asset_bindings' => array(
                'reuse' => true,
                'max_age_seconds' => 3600,
            ),
        ));

        putenv('AI_ASSET_BINDINGS_REUSE=0');
        putenv('OPENAI_ASSET_BINDINGS_REUSE=1');
        putenv('AI_ASSET_BINDINGS_MAX_AGE_SECONDS=120');
        putenv('OPENAI_ASSET_BINDINGS_MAX_AGE_SECONDS=30');

        $policy = AssetBindingPolicy::fromConfig($config, 'openai');

        $this->assertTrue($policy->reuse());
        $this->assertSame(30, $policy->maxAgeSeconds());
    }

    public function testShouldReuseReturnsFalseForExpiredBinding()
    {
        $policy = new AssetBindingPolicy(array(
            'reuse' => true,
            'max_age_seconds' => 60,
        ));

        $binding = new ProviderAssetBinding();
        $binding->updatedAt(date('c', time() - 3600));

        $this->assertFalse($policy->shouldReuse($binding));
    }

    public function testResolverSkipsExpiredBindingAndRefreshesLastUsedMetadata()
    {
        $asset = new Asset();
        $asset->id('asset_1')->kind('file')->mimeType('application/pdf');

        $expiredBinding = new ProviderAssetBinding();
        $expiredBinding->id('binding_old');
        $expiredBinding->assetId('asset_1');
        $expiredBinding->provider('openai');
        $expiredBinding->providerAssetId('file_old');
        $expiredBinding->purpose('user_data');
        $expiredBinding->updatedAt(date('c', time() - 3600));

        $store = new TestAssetStore($expiredBinding);
        $policy = new AssetBindingPolicy(array(
            'reuse' => true,
            'max_age_seconds' => 60,
            'track_last_used_at' => true,
        ));

        $provider = new class implements AssetProviderInterface {
            public function providerName()
            {
                return 'openai';
            }

            public function ensureBinding(Asset $asset, $purpose = null, ProviderAssetBinding $existingBinding = null)
            {
                if ($existingBinding instanceof ProviderAssetBinding) {
                    return $existingBinding;
                }

                $binding = new ProviderAssetBinding();
                $binding->id('binding_new');
                $binding->assetId($asset->id());
                $binding->provider('openai');
                $binding->providerAssetId('file_new');
                $binding->purpose($purpose);
                $binding->status('ready');
                return $binding;
            }
        };

        $resolver = new AssetResolver($store, $policy);
        $binding = $resolver->resolveBinding($provider, $asset, 'user_data');

        $this->assertSame('binding_new', $binding->id());
        $this->assertSame('file_new', $binding->providerAssetId());
        $this->assertNotEmpty($binding->metadata('last_used_at'));
    }
}

class TestAssetStore extends NullAssetStore
{
    /** @var ProviderAssetBinding|false */
    protected $binding;

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

    public function findBinding($assetId, $provider, $purpose = null)
    {
        return $this->binding;
    }

    public function saveBinding(ProviderAssetBinding $binding)
    {
        $this->binding = $binding;
        return $binding;
    }
}
