import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import express from 'express';
import request from 'supertest';

// --- Existing frontend/engine tests omitted for brevity ---

// --- Backend Unit Tests ---

// Mock Db class for backend logic tests
class MockDb {
    constructor() {
        this.data = {};
        this.lastId = 0;
    }
    async getId() { return this.lastId; }
    async create(collection, obj) {
        this.lastId++;
        obj.id = this.lastId;
        this.data[obj.id] = obj;
        return obj;
    }
    async get(collection, query) {
        return Object.values(this.data).find(o => o.id === query.id);
    }
    async update(collection, key, value) {
        if (this.data[key.id]) {
            this.data[key.id] = { ...this.data[key.id], ...value };
            return this.data[key.id];
        }
        return null;
    }
    async remove(collection, key) {
        delete this.data[key.id];
        return true;
    }
    async list(collection, { query }) {
        return Object.values(this.data).filter(o => !query || o.id === query.id);
    }
}

// Example minimal GamesManager using the above mock
class GamesManager {
    init(app) {
        const db = app.db;
        this.create = async (ctx, data) => {
            data.id = await db.getId('games');
            await db.create('games', data);
            return data;
        };
        this.read = async (id) => {
            return await db.get('games', { id });
        };
        this.update = async (ctx, data) => {
            await db.update('games', { id: data.id }, data);
            return data;
        };
        this.remove = async (id) => {
            await db.remove('games', { id });
        };
        this.list = async (query) => {
            return await db.list('games', { query });
        };
    }
}

describe('GamesManager backend logic', () => {
    let app, manager;
    beforeEach(() => {
        app = { db: new MockDb() };
        manager = new GamesManager();
        manager.init(app);
    });

    it('should create, read, update, list, and remove a game', async () => {
        const ctx = {};
        const game = await manager.create(ctx, { name: 'Test Game' });
        expect(game.id).toBe(1);
        expect(game.name).toBe('Test Game');

        const readGame = await manager.read(1);
        expect(readGame.name).toBe('Test Game');

        await manager.update(ctx, { id: 1, name: 'Updated Game' });
        const updatedGame = await manager.read(1);
        expect(updatedGame.name).toBe('Updated Game');

        const list = await manager.list({});
        expect(list.length).toBe(1);

        await manager.remove(1);
        const afterRemove = await manager.read(1);
        expect(afterRemove).toBeUndefined();
    });
});

// --- API Tests (Express) ---

// Minimal API controller for Games
function createGamesApi(manager) {
    const app = express();
    app.use(express.json());
    app.get('/api/game/:id', async (req, res) => {
        const obj = await manager.read(parseInt(req.params.id));
        if (obj) res.json(obj);
        else res.status(404).json({ error: 'Not found' });
    });
    app.post('/api/game', async (req, res) => {
        const list = await manager.list(req.body || {});
        res.json(list);
    });
    app.put('/api/game', async (req, res) => {
        const obj = req.body;
        if (obj.id) {
            await manager.update({}, obj);
            res.json({ status: 'OK', object: obj });
        } else {
            const created = await manager.create({}, obj);
            res.json({ status: 'OK', object: created });
        }
    });
    app.delete('/api/game/:id', async (req, res) => {
        await manager.remove(parseInt(req.params.id));
        res.json({ status: 'OK' });
    });
    return app;
}

describe('Games API', () => {
    let manager, api;
    beforeEach(() => {
        manager = new GamesManager();
        manager.init({ db: new MockDb() });
        api = createGamesApi(manager);
    });

    it('should create and fetch a game via API', async () => {
        const createRes = await request(api)
            .put('/api/game')
            .send({ name: 'API Game' });
        expect(createRes.body.object.name).toBe('API Game');
        const id = createRes.body.object.id;

        const getRes = await request(api).get(`/api/game/${id}`);
        expect(getRes.body.name).toBe('API Game');
    });

    it('should update a game via API', async () => {
        const createRes = await request(api)
            .put('/api/game')
            .send({ name: 'ToUpdate' });
        const id = createRes.body.object.id;

        const updateRes = await request(api)
            .put('/api/game')
            .send({ id, name: 'Updated via API' });
        expect(updateRes.body.object.name).toBe('Updated via API');
    });

    it('should list games via API', async () => {
        await request(api).put('/api/game').send({ name: 'Game1' });
        await request(api).put('/api/game').send({ name: 'Game2' });
        const listRes = await request(api).post('/api/game').send({});
        expect(listRes.body.length).toBe(2);
    });

    it('should delete a game via API', async () => {
        const createRes = await request(api).put('/api/game').send({ name: 'ToDelete' });
        const id = createRes.body.object.id;
        const delRes = await request(api).delete(`/api/game/${id}`);
        expect(delRes.body.status).toBe('OK');
        const getRes = await request(api).get(`/api/game/${id}`);
        expect(getRes.status).toBe(404);
    });
});