import { spawn } from 'node:child_process';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

import { createGamePostgresConnector } from '@sammo-ts/infra';
import { describe, expect, it } from 'vitest';

const databaseUrl = process.env.PROFILE_SEED_CLI_DATABASE_URL;
const describeDatabase = describe.runIf(Boolean(databaseUrl));
const workspaceRoot = path.resolve(process.cwd(), '../..');

const runSeedCli = async (requestFile: string): Promise<{ code: number | null; output: string }> =>
    new Promise((resolve) => {
        const child = spawn(process.execPath, [path.join(workspaceRoot, 'app/gateway-api/dist/index.js')], {
            cwd: workspaceRoot,
            env: {
                ...process.env,
                DATABASE_URL: databaseUrl,
                GATEWAY_ROLE: 'profile-seed',
                PROFILE_SEED_REQUEST_FILE: requestFile,
            },
            stdio: ['ignore', 'pipe', 'pipe'],
        });
        let output = '';
        child.stdout.on('data', (chunk) => {
            output += chunk.toString();
        });
        child.stderr.on('data', (chunk) => {
            output += chunk.toString();
        });
        child.on('close', (code) => resolve({ code, output }));
    });

describeDatabase('selected workspace profile seed CLI', () => {
    it('seeds through the built gateway artifact with the serialized operation identity', async () => {
        if (!databaseUrl) {
            throw new Error('PROFILE_SEED_CLI_DATABASE_URL is required.');
        }
        const tempDirectory = await fs.mkdtemp(path.join(os.tmpdir(), 'profile-seed-cli-test-'));
        const requestFile = path.join(tempDirectory, 'request.json');
        const connector = createGamePostgresConnector({ url: databaseUrl });
        try {
            await fs.writeFile(
                requestFile,
                JSON.stringify({
                    scenarioId: 1010,
                    tickSeconds: 60,
                    now: '2036-03-03T00:00:00.000Z',
                    installOptions: {
                        serverId: 'selected-cli-seed',
                        installOperationId: 'selected-cli-operation',
                        installCommitSha: 'selected-cli-commit',
                    },
                    adminUser: {
                        id: 'selected-cli-admin',
                        username: 'selected-cli-admin',
                        displayName: '선택 CLI 관리자',
                    },
                }),
                { encoding: 'utf8', mode: 0o600 }
            );

            const result = await runSeedCli(requestFile);
            expect(result, result.output).toMatchObject({ code: 0 });
            await connector.connect();
            const world = await connector.prisma.worldState.findFirstOrThrow();
            expect(world).toMatchObject({
                scenarioCode: '1010',
                meta: {
                    installOperationId: 'selected-cli-operation',
                    installCommitSha: 'selected-cli-commit',
                },
            });
            const adminGeneral = await connector.prisma.general.findFirstOrThrow({
                where: { userId: 'selected-cli-admin' },
            });
            expect(adminGeneral).toMatchObject({ meta: { createdBy: 'admin-seed' } });
            const history = await connector.prisma.gameHistory.findUniqueOrThrow({
                where: { serverId: 'selected-cli-seed' },
            });

            const retry = await runSeedCli(requestFile);
            expect(retry, retry.output).toMatchObject({ code: 0 });
            await expect(connector.prisma.worldState.findFirstOrThrow()).resolves.toEqual(world);
            await expect(
                connector.prisma.general.findFirstOrThrow({ where: { userId: 'selected-cli-admin' } })
            ).resolves.toEqual(adminGeneral);
            await expect(
                connector.prisma.gameHistory.findUniqueOrThrow({ where: { serverId: 'selected-cli-seed' } })
            ).resolves.toEqual(history);
            await expect(
                connector.prisma.gameHistory.count({ where: { serverId: 'selected-cli-seed' } })
            ).resolves.toBe(1);
        } finally {
            await connector.prisma.gameHistory.deleteMany({ where: { serverId: 'selected-cli-seed' } });
            await connector.disconnect();
            await fs.rm(tempDirectory, { recursive: true, force: true });
        }
    });
});
