<?php

declare(strict_types=1);

use App\Framework\Deployment\Pipeline\ValueObjects\DeploymentEnvironment;
use App\Framework\Deployment\Pipeline\ValueObjects\PipelineStage;
use App\Framework\Deployment\Pipeline\ValueObjects\StageConfig;

describe('StageConfig', function () {
    it('creates stage config with default values', function () {
        $config = new StageConfig(stage: PipelineStage::BUILD);

        expect($config->stage)->toBe(PipelineStage::BUILD);
        expect($config->enabled)->toBeTrue();
        expect($config->timeoutSeconds)->toBe(0);
        expect($config->retries)->toBe(0);
        expect($config->continueOnFailure)->toBeFalse();
        expect($config->parameters)->toBeEmpty();
        expect($config->skipEnvironments)->toBeEmpty();
    });

    it('creates stage config with custom values', function () {
        $config = new StageConfig(
            stage: PipelineStage::BUILD,
            enabled: false,
            timeoutSeconds: 300,
            retries: 3,
            continueOnFailure: true,
            parameters: ['key' => 'value'],
            skipEnvironments: [DeploymentEnvironment::DEVELOPMENT]
        );

        expect($config->enabled)->toBeFalse();
        expect($config->timeoutSeconds)->toBe(300);
        expect($config->retries)->toBe(3);
        expect($config->continueOnFailure)->toBeTrue();
        expect($config->parameters)->toHaveKey('key');
        expect($config->skipEnvironments)->toContain(DeploymentEnvironment::DEVELOPMENT);
    });

    it('determines if should skip for environment', function () {
        $config = new StageConfig(
            stage: PipelineStage::BACKUP,
            skipEnvironments: [
                DeploymentEnvironment::DEVELOPMENT,
                DeploymentEnvironment::STAGING
            ]
        );

        expect($config->shouldSkipForEnvironment(DeploymentEnvironment::DEVELOPMENT))->toBeTrue();
        expect($config->shouldSkipForEnvironment(DeploymentEnvironment::STAGING))->toBeTrue();
        expect($config->shouldSkipForEnvironment(DeploymentEnvironment::PRODUCTION))->toBeFalse();
    });

    it('gets parameter with default value', function () {
        $config = new StageConfig(
            stage: PipelineStage::BUILD,
            parameters: ['timeout' => 300]
        );

        expect($config->getParameter('timeout'))->toBe(300);
        expect($config->getParameter('missing', 'default'))->toBe('default');
    });

    it('checks if has timeout', function () {
        $noTimeout = new StageConfig(
            stage: PipelineStage::BUILD,
            timeoutSeconds: 0
        );

        $withTimeout = new StageConfig(
            stage: PipelineStage::BUILD,
            timeoutSeconds: 300
        );

        expect($noTimeout->hasTimeout())->toBeFalse();
        expect($withTimeout->hasTimeout())->toBeTrue();
    });

    it('checks if has retries', function () {
        $noRetries = new StageConfig(
            stage: PipelineStage::BUILD,
            retries: 0
        );

        $withRetries = new StageConfig(
            stage: PipelineStage::BUILD,
            retries: 3
        );

        expect($noRetries->hasRetries())->toBeFalse();
        expect($withRetries->hasRetries())->toBeTrue();
    });

    it('creates default config for build stage', function () {
        $config = StageConfig::forStage(PipelineStage::BUILD);

        expect($config->stage)->toBe(PipelineStage::BUILD);
        expect($config->enabled)->toBeTrue();
        expect($config->timeoutSeconds)->toBe(600); // 10 minutes
        expect($config->retries)->toBe(1);
    });

    it('creates default config for test stage', function () {
        $config = StageConfig::forStage(PipelineStage::TEST);

        expect($config->stage)->toBe(PipelineStage::TEST);
        expect($config->timeoutSeconds)->toBe(300); // 5 minutes
        expect($config->retries)->toBe(0);
        expect($config->skipEnvironments)->toContain(DeploymentEnvironment::PRODUCTION);
    });

    it('creates default config for security check stage', function () {
        $config = StageConfig::forStage(PipelineStage::SECURITY_CHECK);

        expect($config->stage)->toBe(PipelineStage::SECURITY_CHECK);
        expect($config->timeoutSeconds)->toBe(120); // 2 minutes
        expect($config->skipEnvironments)->toContain(DeploymentEnvironment::DEVELOPMENT);
    });

    it('creates default config for backup stage', function () {
        $config = StageConfig::forStage(PipelineStage::BACKUP);

        expect($config->stage)->toBe(PipelineStage::BACKUP);
        expect($config->timeoutSeconds)->toBe(300); // 5 minutes
        expect($config->retries)->toBe(1);
        expect($config->skipEnvironments)->toContain(DeploymentEnvironment::DEVELOPMENT);
    });

    it('creates default config for deploy stage', function () {
        $config = StageConfig::forStage(PipelineStage::DEPLOY);

        expect($config->stage)->toBe(PipelineStage::DEPLOY);
        expect($config->timeoutSeconds)->toBe(600); // 10 minutes
        expect($config->retries)->toBe(0);
    });

    it('creates default config for health check stage', function () {
        $config = StageConfig::forStage(PipelineStage::HEALTH_CHECK);

        expect($config->stage)->toBe(PipelineStage::HEALTH_CHECK);
        expect($config->timeoutSeconds)->toBe(60); // 1 minute
        expect($config->retries)->toBe(2);
    });

    it('creates default config for cleanup stage', function () {
        $config = StageConfig::forStage(PipelineStage::CLEANUP);

        expect($config->stage)->toBe(PipelineStage::CLEANUP);
        expect($config->timeoutSeconds)->toBe(180); // 3 minutes
        expect($config->continueOnFailure)->toBeTrue();
    });

    it('creates default config for rollback stage', function () {
        $config = StageConfig::forStage(PipelineStage::ROLLBACK);

        expect($config->stage)->toBe(PipelineStage::ROLLBACK);
        expect($config->timeoutSeconds)->toBe(300); // 5 minutes
        expect($config->retries)->toBe(0);
    });
});
