<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>

        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <!-- Neutralize the deployed bootstrap caches. With bootstrap/cache/
             config.php present (this box runs `artisan config:cache`), every
             <env> below is silently IGNORED — the suite then runs against the
             LIVE production database (only `migrate:fresh` refusing to run in
             APP_ENV=production stands between that and dropping it). Pointing
             the cache paths at files that never exist makes phpunit always
             load the real config files, which honour these overrides. -->
        <env name="APP_CONFIG_CACHE" value="bootstrap/cache/config.phpunit.php" force="true"/>
        <env name="APP_SERVICES_CACHE" value="bootstrap/cache/services.phpunit.php" force="true"/>
        <env name="APP_PACKAGES_CACHE" value="bootstrap/cache/packages.phpunit.php" force="true"/>
        <env name="APP_ROUTES_CACHE" value="bootstrap/cache/routes.phpunit.php" force="true"/>
        <env name="APP_EVENTS_CACHE" value="bootstrap/cache/events.phpunit.php" force="true"/>
        <env name="APP_ENV" value="testing" force="true"/>
        <!-- Legacy Dingo (unused — no Dingo routes exist) hijacks every /api/*
             request when API_PREFIX is set and 400s on its strict Accept-header
             check. Blank it so the stateless APIs (/api/agent-*, and later the
             mini-program surface) stay reachable in tests regardless of the
             developer's local .env. -->
        <env name="API_PREFIX" value="" force="true"/>
        <env name="API_STRICT" value="false" force="true"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_MAILER" value="array" force="true"/>
        <!-- The customer contact-verification gate is ON in the suite whatever the
             developer's .env says; the VERIFY_USERS=off tests set the config themselves. -->
        <env name="VERIFY_USERS" value="on" force="true"/>
        <env name="FEATURE_PROJECTS_ENABLED" value="true"/>
        <env name="FEATURE_VIDEO_ENABLED" value="true"/>
        <!--
            The four conversation release controls used to be pinned OFF here
            with force="true", because a developer's own .env could otherwise
            flip every flag-off assertion in the suite into a passing tautology.
            They are database settings now (Src\Setting\Setting::CONVERSATION_FEATURES),
            so each test starts from an empty `settings` table — off by default,
            with nothing in the environment able to change that — and switches
            what it needs via Tests\Concerns\InteractsWithConversationFeatures.
        -->
        <!-- The Analyze Property lockdown is a TEMPORARY operational switch, not
             behaviour of the module — off here so its own suite keeps testing the
             real pages. AnalyzePropertyLockdownTest turns it back on to cover the lock. -->
        <env name="ANALYZE_PROPERTY_LOCKED" value="false" force="true"/>
        <!-- Same arrangement for the Area Guide: AreaGuideLockdownTest turns
             this one back on to cover its lock. -->
        <env name="AREA_GUIDE_LOCKED" value="false" force="true"/>
        <!-- And for the two switches that narrow the guide for READERS while
             its content is being written: the per-area assistant stays ON and
             no area is pinned, so the suite exercises the whole guide. Their
             own tests turn each one on to cover it. Pinned here because a
             developer's .env carries them, and phpunit reads .env. -->
        <env name="AREA_GUIDE_CHAT_ENABLED" value="true" force="true"/>
        <env name="AREA_GUIDE_PINNED_AREA" value="" force="true"/>
        <!-- Tests assert absolute URLs (portal redirects, CAPI payloads, Notify
             links), so the host must not depend on a developer's local APP_URL. -->
        <env name="APP_URL" value="https://petav3.test" force="true"/>
        <env name="DB_CONNECTION" value="mysql" force="true"/>
        <env name="DB_HOST" value="127.0.0.1" force="true"/>
        <env name="DB_PORT" value="3306" force="true"/>
        <env name="DB_DATABASE" value="petav3_testing" force="true"/>
        <env name="DB_USERNAME" value="root" force="true"/>
        <env name="DB_PASSWORD" value="" force="true"/>
        <!-- The catalogue connection collapses onto the DEFAULT testing
             database, so the suite runs single-database whatever .env points
             the real MASTER_DB_* values at (they are the live remote master
             once a deployment is cut over). One switch, not five values that
             have to agree — and TestCase::shareCatalogueConnection() then puts
             both handles on one PDO session. -->
        <env name="CATALOGUE_USE_DEFAULT_CONNECTION" value="true" force="true"/>
        <!-- catalogue_master deliberately ignores the collapse switch. Pin its
             own credentials too, before any service provider can resolve it. -->
        <env name="MASTER_DB_HOST" value="127.0.0.1" force="true"/>
        <env name="MASTER_DB_PORT" value="3306" force="true"/>
        <env name="MASTER_DB_DATABASE" value="petav3_testing" force="true"/>
        <env name="MASTER_DB_USERNAME" value="root" force="true"/>
        <env name="MASTER_DB_PASSWORD" value="" force="true"/>
        <env name="AREA_GUIDE_CONTENT_CONNECTION" value="catalogue" force="true"/>
        <env name="AREA_GUIDE_CONTENT_SOURCE" value="legacy" force="true"/>
        <env name="AREA_GUIDE_CONTENT_EDITING" value="false" force="true"/>
        <env name="AREA_GUIDE_MAP_ENABLED" value="false" force="true"/>
        <env name="INSPECTOR_ENABLE" value="false" force="true"/>
        <env name="AREA_GUIDE_LOCAL_DATABASE" value="petav3_testing" force="true"/>
        <!-- The suite makes catalogue writes from `localhost`; the domain gate
             would 403 them all. `*` disables it — the gate's own tests re-pin
             the domain list via config() to prove both sides. -->
        <env name="CATALOGUE_EDIT_DOMAINS" value="*" force="true"/>
        <env name="PETAV2_DB_HOST" value="127.0.0.1"/>
        <env name="PETAV2_DB_PORT" value="3306"/>
        <env name="PETAV2_DB_DATABASE" value="petav2_test"/>
        <env name="PETAV2_DB_USERNAME" value="root"/>
        <env name="PETAV2_DB_PASSWORD" value=""/>
        <!-- Force the transcription job lane to sync so tests don't need Redis.
             Mirrors the pattern AiJob uses (config('ai.queue_connection')).
             Without this, TranscribeCallRecording::onConnection('redis-transcription')
             overrides QUEUE_DRIVER=sync and tries to actually connect to Redis. -->
        <env name="TRANSCRIPTION_QUEUE_CONNECTION" value="sync"/>
        <!-- Same, for the micro-site extraction lane. ExtractResourceSite pins
             itself to redis-video in production; sync here so a test that
             uploads an archive gets it unpacked inline instead of needing a
             worker. SiteResourceTest asserts the QUEUING separately, so this
             does not hide the fact that it is queued in production. -->
        <env name="AI_SITE_QUEUE_CONNECTION" value="sync"/>
        <!-- Call pipeline providers: force OFF in tests so real .env keys never
             leak in and make the suite non-hermetic. Each test sets what it needs
             via config([...]). -->
        <env name="DEEPGRAM_API_KEY" value=""/>
        <env name="GEMINI_API_KEY" value=""/>
        <env name="DOWAYAI_POLL_ENABLED" value="false"/>
        <env name="REFERENCE_DB_HOST" value="127.0.0.1" force="true"/>
        <env name="REFERENCE_DB_PORT" value="3306" force="true"/>
        <env name="REFERENCE_DB_DATABASE" value="petav3_testing" force="true"/>
        <env name="REFERENCE_DB_USERNAME" value="root" force="true"/>
        <env name="REFERENCE_DB_PASSWORD" value="" force="true"/>
        <env name="JWT_SECRET" value="agent-api-testing-secret-key-0123456789abcdef" force="true"/>
        <!--
            Storage is LOCAL under test. `.env.example` points MEDIA_DISK at gcs, which
            is right for a real deployment and wrong for a test run: the Google client
            wants storage/app/google/service-account.json and throws GoogleException
            when it is absent. A test must never need cloud credentials to pass — this
            failed on CI and passed on a developer's laptop purely because that laptop
            happened to have MEDIA_DISK=public in its own .env, which is exactly the
            machine-dependent result a suite exists to avoid. `force` for the same
            reason every value above carries it: a developer's .env must not win here.
        -->
        <env name="MEDIA_DISK" value="public" force="true"/>
    </php>
</phpunit>
