import fs from 'node:fs/promises';
import path from 'node:path';
import { randomUUID } from 'node:crypto';

import { createRedisConnector, resolveRedisConfigFromEnv } from '@sammo-ts/infra';
import { afterEach, describe, expect, it, vi } from 'vitest';

import { buildBattleSimEnvironment } from '../src/battleSim/environment.js';
import { buildBattleSimQueueKeys } from '../src/battleSim/keys.js';
import { RedisBattleSimTransport } from '../src/battleSim/redisTransport.js';
import type { BattleSimRequestPayload } from '../src/battleSim/types.js';
import { runBattleSimWorker } from '../src/battleSim/worker.js';
import type { WorldStateRow } from '../src/context.js';

const liveDescribe = process.env.REDIS_URL ? describe : describe.skip;

afterEach(() => {
    vi.unstubAllEnvs();
});

liveDescribe('battle simulator worker with live Redis', () => {
    it('consumes an isolated queue, produces a result, and stops cleanly', { timeout: 30_000 }, async () => {
        const namespace = process.env.CONDITIONAL_INTEGRATION_RUN_ID ?? randomUUID();
        const scenario = `battle-sim-e2e-${namespace}-${randomUUID()}`;
        const profileName = `che:${scenario}`;
        const requesterUserId = 'worker-e2e-user';
        vi.stubEnv('PROFILE', 'che');
        vi.stubEnv('SCENARIO', scenario);
        vi.stubEnv('GAME_TOKEN_SECRET', 'battle-sim-test-only');

        const fixturePath = path.resolve(
            process.cwd(),
            '../../tools/integration-tests/fixtures/battle/basic-infantry.json'
        );
        const fixture = JSON.parse(await fs.readFile(fixturePath, 'utf8')) as BattleSimRequestPayload & {
            startYear: number;
        };
        const { startYear, ...request } = fixture;
        const worldState: WorldStateRow = {
            id: 1,
            scenarioCode: 'default',
            currentYear: request.year,
            currentMonth: request.month,
            tickSeconds: 600,
            config: {},
            meta: { scenarioMeta: { startYear } },
            updatedAt: new Date(),
        };
        const environment = await buildBattleSimEnvironment(worldState, 'che');
        const payload = {
            ...request,
            unitSet: environment.unitSet,
            config: environment.config,
            time: { year: request.year, month: request.month, startYear },
            scenarioEffect: environment.scenarioEffect,
        };

        const clientConnector = createRedisConnector(resolveRedisConfigFromEnv());
        await clientConnector.connect();
        const keys = buildBattleSimQueueKeys(profileName);
        const transport = new RedisBattleSimTransport(clientConnector.client, {
            keys,
            requestTimeoutMs: 15_000,
            resultTtlSeconds: 60,
        });
        const abortController = new AbortController();
        const worker = runBattleSimWorker({ signal: abortController.signal });
        let jobId: string | null = null;

        try {
            const result = await transport.simulate(payload, requesterUserId);
            jobId = result.jobId;
            expect(result.status).toBe('completed');
            if (result.status === 'completed') {
                expect(result.payload).toMatchObject({
                    result: true,
                    reason: 'success',
                    avgWar: 1,
                });
                expect(result.payload.phase).toBeGreaterThan(0);
            }
        } finally {
            abortController.abort();
            await worker;
            if (jobId) {
                const encodedRequester = encodeURIComponent(requesterUserId);
                await clientConnector.client.del([
                    keys.queueKey,
                    `${keys.resultKeyPrefix}${encodedRequester}:${jobId}`,
                    `${keys.notifyKeyPrefix}${encodedRequester}:${jobId}`,
                ]);
            }
            await clientConnector.disconnect();
        }
    });
});
