/**
 * CLI + MCP parity tests for DDIC (DOMA / DTEL / TABL / STRUCT) and
 * CDS (DDLS / DCLS) object operations.
 *
 * Both paths are driven against the same mock ADT backend through the
 * shared harness (see ./harness.ts). Each test verifies that the CLI
 * command and the equivalent MCP tool both succeed end-to-end against
 * the same in-memory server.
 *
 * NOTE on CLI argument shapes: the CRUD commands generated by
 * `buildObjectCrudCommands` use *positional* arguments
 *   <name> <description> <package>
 * (no `--package` flag) and `-y / --yes` for delete confirmation
 * (no `--force`). The task spec listed `--package` / `--force` for
 * convenience; the actual flags discovered in the source are used here.
 *
 * NOTE on MCP argument names: the get_* tools for DDIC/CDS objects use
 * type-specific argument names (`domainName`, `dataElementName`,
 * `tableName`, `structureName`, `ddlName`, `dclName`), not a generic
 * `name` field – verified against packages/adt-mcp/src/lib/tools/*.
 */

import { describe, it, expect, beforeAll, afterAll } from 'vitest';
import {
  startAdtHarness,
  runCliCommand,
  callMcpTool,
  type AdtHarness,
} from './index';

describe('CLI + MCP parity: DDIC & CDS', () => {
  let harness: AdtHarness;

  beforeAll(async () => {
    harness = await startAdtHarness();
  }, 30_000);

  afterAll(async () => {
    if (harness) await harness.stop();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 1. Read domain
  // ─────────────────────────────────────────────────────────────────────
  it('1. reads a domain (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['domain', 'read', 'ZDOMAIN_X']);
    expect(cli.exitCode).toBe(0);
    expect(cli.stdout.length).toBeGreaterThan(0);

    const mcp = await callMcpTool(harness, 'get_domain', {
      domainName: 'ZDOMAIN_X',
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 2. Create domain
  // ─────────────────────────────────────────────────────────────────────
  it('2. creates a domain (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'domain',
      'create',
      'ZD_NEW',
      'Test domain',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'DOMA',
      objectName: 'ZD_NEW',
      description: 'Test domain',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 3. Delete domain
  // ─────────────────────────────────────────────────────────────────────
  it('3. deletes a domain (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'domain',
      'delete',
      'ZD_NEW',
      '-y',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'delete_object', {
      objectType: 'DOMA',
      objectName: 'ZD_NEW',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 4. Read data element
  // ─────────────────────────────────────────────────────────────────────
  it('4. reads a data element (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['dataelement', 'read', 'ZDTEL']);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'get_data_element', {
      dataElementName: 'ZDTEL',
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 5. Create data element
  // ─────────────────────────────────────────────────────────────────────
  it('5. creates a data element (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'dataelement',
      'create',
      'ZDTEL_NEW',
      'Test data element',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'DTEL',
      objectName: 'ZDTEL_NEW',
      description: 'Test data element',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 6. Read table
  // ─────────────────────────────────────────────────────────────────────
  it('6. reads a table (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['table', 'read', 'ZTAB']);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'get_table', {
      tableName: 'ZTAB',
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 7. Create table
  // ─────────────────────────────────────────────────────────────────────
  it('7. creates a table (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'table',
      'create',
      'ZTAB_NEW',
      'Test table',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'TABL',
      objectName: 'ZTAB_NEW',
      description: 'Test table',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 8. Read structure
  // ─────────────────────────────────────────────────────────────────────
  it('8. reads a structure (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['structure', 'read', 'ZSTRUCT']);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'get_structure', {
      structureName: 'ZSTRUCT',
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 9. Create structure
  // ─────────────────────────────────────────────────────────────────────
  it('9. creates a structure (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'structure',
      'create',
      'ZSTRUCT_NEW',
      'Test structure',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'STRUCT',
      objectName: 'ZSTRUCT_NEW',
      description: 'Test structure',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 10. Read DDL (CDS)
  // ─────────────────────────────────────────────────────────────────────
  it('10. reads a CDS DDL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['ddl', 'read', 'ZI_DDL']);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'get_cds_ddl', {
      ddlName: 'ZI_DDL',
      includeSource: true,
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 11. Create DDL
  // ─────────────────────────────────────────────────────────────────────
  it('11. creates a CDS DDL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'ddl',
      'create',
      'ZI_NEW',
      'Test DDL view',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'DDLS',
      objectName: 'ZI_NEW',
      description: 'Test DDL view',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 12. Delete DDL
  // ─────────────────────────────────────────────────────────────────────
  it('12. deletes a CDS DDL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'ddl',
      'delete',
      'ZI_NEW',
      '-y',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'delete_object', {
      objectType: 'DDLS',
      objectName: 'ZI_NEW',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 13. Read DCL (CDS)
  // ─────────────────────────────────────────────────────────────────────
  it('13. reads a CDS DCL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, ['dcl', 'read', 'ZI_DCL']);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'get_cds_dcl', {
      dclName: 'ZI_DCL',
      includeSource: true,
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });

  // ─────────────────────────────────────────────────────────────────────
  // 14. Create DCL
  // ─────────────────────────────────────────────────────────────────────
  it('14. creates a CDS DCL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'dcl',
      'create',
      'ZI_DCL_NEW',
      'Test DCL',
      '$TMP',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'create_object', {
      objectType: 'DCLS',
      objectName: 'ZI_DCL_NEW',
      description: 'Test DCL',
      packageName: '$TMP',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 15. Delete DCL
  // ─────────────────────────────────────────────────────────────────────
  it('15. deletes a CDS DCL source (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'dcl',
      'delete',
      'ZI_DCL_NEW',
      '-y',
      '--json',
    ]);
    expect(cli.exitCode).toBe(0);

    const mcp = await callMcpTool(harness, 'delete_object', {
      objectType: 'DCLS',
      objectName: 'ZI_DCL_NEW',
    });
    expect(mcp.isError).toBe(false);
  });

  // ─────────────────────────────────────────────────────────────────────
  // 16. Read table source via `source get` (CLI + MCP get_source)
  // ─────────────────────────────────────────────────────────────────────
  it('16. reads table source via `source get` (CLI + MCP)', async () => {
    const cli = await runCliCommand(harness, [
      'source',
      'get',
      'ZTAB',
      '--type',
      'TABL',
    ]);
    expect(cli.exitCode).toBe(0);
    expect(cli.stdout.length).toBeGreaterThan(0);

    const mcp = await callMcpTool(harness, 'get_source', {
      objectName: 'ZTAB',
      objectType: 'TABL',
    });
    expect(mcp.isError).toBe(false);
    expect(mcp.json).toBeDefined();
  });
});
