import fs from 'fs';
import path from 'path';

const html = fs.readFileSync(path.join(process.cwd(), 'public/metadata-viewer.html'), 'utf8');
const scriptMatch = html.match(/<script>([\s\S]*)<\/script>/);
if (!scriptMatch) {
  console.error('Cannot extract <script> from public/metadata-viewer.html');
  process.exit(1);
}
const jsCode = scriptMatch[1];

function createNode(id) {
  return {
    id,
    dataset: {},
    style: { display: '', minWidth: '', minHeight: '' },
    innerHTML: '',
    textContent: '',
    children: [],
    className: '',
    onclick: null,
    onmouseenter: null,
    onmouseleave: null,
    appendChild(child) { this.children.push(child); return child; },
    setAttribute() {},
    getAttribute() { return null; },
    querySelectorAll() { return []; },
  };
}

const elements = {};
function $(id) {
  if (!elements[id]) elements[id] = createNode(id);
  return elements[id];
}

global.document = {
  getElementById: (id) => $(id),
  createElement: (tag) => createNode(`${tag}-${Math.random()}`),
  createElementNS: (ns, tag) => createNode(`${tag}-${Math.random()}`),
};
global.window = {
  parent: { postMessage() {} },
  addEventListener() {},
  removeEventListener() {},
};
global.addEventListener = () => {};

eval(`(function(){
  ${jsCode}
  global._metadataViewer = {
    parseMeta,
    getState: () => ({ nodes, connections }),
  };
})()`);

let passed = 0;
let failed = 0;

function test(name, fn) {
  try {
    fn();
    console.log(`  ✓ ${name}`);
    passed++;
  } catch (e) {
    console.log(`  ✗ ${name}: ${e.message}`);
    failed++;
  }
}

function assert(cond, msg) {
  if (!cond) throw new Error(msg || 'Assertion failed');
}

function getCounts() {
  const { nodes, connections } = global._metadataViewer.getState();
  const counts = nodes.reduce((acc, node) => {
    acc[node.type] = (acc[node.type] || 0) + 1;
    return acc;
  }, {});
  return { nodes, connections, counts };
}

console.log('\n── Metadata Viewer Regression ──');

test('renders legacy database.tables even before apps/services exist', () => {
  global._metadataViewer.parseMeta({
    project: { name: 'PartialLegacy' },
    database: {
      name: 'PartialLegacy',
      tables: [
        { name: 'Courses', fields: [{ name: 'title', type: 'STRING' }] },
        { name: 'PrepNotes', fields: [{ name: 'courseId', type: 'INT' }] },
      ],
    },
    serviceDomains: [],
    components: [],
    sections: [],
    apps: [],
  });

  const { counts } = getCounts();
  assert(counts.table === 2, `Expected 2 table nodes, got ${counts.table || 0}`);
});

test('uses legacy sourceTable for VT labels and table connections', () => {
  global._metadataViewer.parseMeta({
    project: { name: 'LegacySourceTable' },
    database: {
      name: 'LegacySourceTable',
      tables: [
        { name: 'Courses', fields: [{ name: 'title', type: 'STRING' }] },
      ],
    },
    serviceDomains: [
      {
        domainId: 'Course',
        virtualTables: [
          {
            name: 'CourseList',
            sourceTable: 'Courses',
            fields: [{ name: 'title', type: 'STRING' }],
          },
        ],
        services: [
          { serviceId: 'Course.GetCourseList', name: 'GetCourseList' },
        ],
      },
    ],
    components: [],
    sections: [],
    apps: [],
  });

  const { nodes, connections, counts } = getCounts();
  const vtNode = nodes.find((node) => node.id === 'Course.CourseList');
  assert(vtNode, 'Expected Course.CourseList VT node');
  assert(vtNode.sub === 'source: Courses', `Expected VT source label, got ${vtNode.sub}`);
  assert(counts.table === 1, `Expected 1 table node, got ${counts.table || 0}`);
  assert(connections.some((conn) => conn.from === 'Course.CourseList' && conn.to === 'Courses' && conn.type === 'data'),
    'Expected VT → table data connection');
});

test('connects app page sectionRefs and section servicesUsed from extracted metadata', () => {
  global._metadataViewer.parseMeta({
    project: { name: 'TeacherPrep' },
    apps: [
      {
        appId: 'TeacherPrepApp',
        pages: [
          {
            pageId: 'Main',
            sectionRefs: [
              { sectionId: 'NavSidebar', instanceId: 'navSidebar' },
              { sectionId: 'DashboardMain', instanceId: 'dashboardMain' },
            ],
            componentRefs: [
              { componentId: 'ConfirmDialog', instanceId: 'confirmDialog' },
            ],
            routeMap: {
              dashboard: 'DashboardMain',
            },
          },
        ],
      },
    ],
    sections: [
      {
        sectionId: 'DashboardMain',
        servicesUsed: [
          {
            domainId: 'Dashboard',
            services: [
              { serviceId: 'Dashboard.GetStats', serviceName: 'GetStats' },
            ],
          },
        ],
      },
      { sectionId: 'NavSidebar' },
    ],
    components: [
      { componentId: 'ConfirmDialog' },
    ],
    services: [
      {
        domainId: 'Dashboard',
        methods: [
          { name: 'GetStats' },
        ],
      },
    ],
    dataSchema: { tables: [] },
  });

  const { connections } = getCounts();
  assert(connections.some((conn) => conn.from === 'Main' && conn.to === 'DashboardMain' && conn.type === 'ui'),
    'Expected page → section connection from sectionRefs/routeMap');
  assert(connections.some((conn) => conn.from === 'Main' && conn.to === 'ConfirmDialog' && conn.type === 'comp'),
    'Expected page → component connection from componentRefs');
  assert(connections.some((conn) => conn.from === 'DashboardMain' && conn.to === 'Dashboard.GetStats' && conn.type === 'service'),
    'Expected section → service connection from servicesUsed');
});

console.log(`\n── Results ──\n\n  ${passed} passed, ${failed} failed\n`);
process.exit(failed > 0 ? 1 : 0);
