import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import { mkdtempSync, readFileSync, rmSync, copyFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join, resolve } from 'node:path';
import { devIndicesPlugin } from '../index';

const FIXTURE = resolve(__dirname, 'fixtures/sample.vue');

function runTransform(filePath: string, manifestPath: string) {
    const plugin = devIndicesPlugin({
        manifestPath,
        appRoot: resolve(__dirname, '..', '..', '..'),
        enabled: true,
    });
    // buildStart loads existing manifest (or createEmpty() if missing)
    if (typeof plugin.buildStart === 'function') (plugin.buildStart as Function).call({});
    const source = readFileSync(filePath, 'utf8');
    const result = (plugin.transform as Function).call({}, source, filePath);
    // buildEnd flushes manifest to disk
    if (typeof plugin.buildEnd === 'function') (plugin.buildEnd as Function).call({});
    return result?.code ?? result;
}

describe('vite-plugin-dev-indices integration', () => {
    let dir: string;
    let manifestPath: string;
    let workingFixture: string;

    beforeEach(() => {
        dir = mkdtempSync(join(tmpdir(), 'dx-int-'));
        manifestPath = join(dir, 'dev-indices.json');
        workingFixture = join(dir, 'sample.vue');
        copyFileSync(FIXTURE, workingFixture);
    });

    afterEach(() => rmSync(dir, { recursive: true, force: true }));

    it('injects data-dx attributes into every element', () => {
        const code = runTransform(workingFixture, manifestPath);
        expect(code).toMatch(/<div class="root" data-dx="\d+">/);
        expect(code).toMatch(/<v-btn icon="plus" data-dx="\d+">/);
        expect(code).toMatch(/<v-btn icon="user" data-dx="\d+">/);
        expect(code).toMatch(/<v-list data-dx="\d+">/);
        expect(code).toMatch(/<v-list-item v-for="i in 3" :key="i" data-dx="\d+">/);
    });

    it('writes manifest with one entry per element', () => {
        runTransform(workingFixture, manifestPath);
        const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
        // 5 elements in fixture (div, 2 v-btn, v-list, v-list-item)
        expect(Object.keys(manifest.entries)).toHaveLength(5);
        expect(manifest.lastId).toBe(5);
    });

    it('second run on unchanged file produces identical IDs', () => {
        const code1 = runTransform(workingFixture, manifestPath);
        const code2 = runTransform(workingFixture, manifestPath);
        expect(code1).toBe(code2);
        const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
        expect(manifest.lastId).toBe(5);
    });

    it('returns null for non-.vue files', () => {
        const plugin = devIndicesPlugin({ manifestPath, appRoot: dir, enabled: true });
        expect((plugin.transform as Function).call({}, '// js', '/foo/bar.ts')).toBeNull();
    });

    it('returns null when disabled', () => {
        const plugin = devIndicesPlugin({ manifestPath, appRoot: dir, enabled: false });
        const source = readFileSync(workingFixture, 'utf8');
        expect((plugin.transform as Function).call({}, source, workingFixture)).toBeNull();
    });
});
