import { describe, it, expect } from "vitest";
import { ejectIntent } from "../../src/core/eject.js";

const VALID_SOURCE = `
import { defineIntent, param } from "@axint/sdk";

export default defineIntent({
  name: "SendMessage",
  title: "Send Message",
  description: "Sends a message to a contact",
  params: {
    recipient: param.string("Who to message"),
    body: param.string("Message content"),
  },
  perform: async ({ recipient, body }) => {
    return { sent: true };
  },
});
`;

describe("ejectIntent", () => {
  it("ejects valid source to standalone Swift", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.swiftFile).toBeDefined();
    expect(result.swiftFile.path).toContain("SendMessageIntent.swift");
    expect(result.swiftFile.content).toContain("struct SendMessageIntent: AppIntent");
  });

  it("removes Axint regeneration instruction from header", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.swiftFile.content).not.toContain(
      "Re-run `axint compile` to regenerate"
    );
    expect(result.swiftFile.content).not.toContain("Do not edit manually");
  });

  it("preserves ejected code is standalone", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.swiftFile.content).not.toContain("axint compile");
    expect(result.swiftFile.content).toContain("import AppIntents");
    expect(result.swiftFile.content).toContain("import Foundation");
  });

  it("includes original Axint attribution in header", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.swiftFile.content).toContain("Originally generated by Axint");
    expect(result.swiftFile.content).toContain("https://github.com/agenticempire/axint");
  });

  it("replaces TODO comment with helpful documentation reference", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.swiftFile.content).toContain(
      "// TODO: Implement your intent logic here."
    );
    expect(result.swiftFile.content).toContain(
      "For more information about App Intents, see:"
    );
    expect(result.swiftFile.content).toContain(
      "https://developer.apple.com/documentation/appintents"
    );
  });

  it("generates test file when includeTests is true", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts", {
      includeTests: true,
    });

    expect(result.testFile).toBeDefined();
    expect(result.testFile!.path).toContain("SendMessageIntentTests.swift");
    expect(result.testFile!.content).toContain("final class SendMessageIntentTests");
    expect(result.testFile!.content).toContain("func testIntentInitialization");
    expect(result.testFile!.content).toContain("func testIntentPerform");
    expect(result.testFile!.content).toContain("import XCTest");
  });

  it("does not generate test file by default", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts");

    expect(result.testFile).toBeUndefined();
  });

  it("emits Info.plist fragment when intent has plist keys", async () => {
    const sourceWithPlist = `
import { defineIntent, param } from "@axint/sdk";

export default defineIntent({
  name: "GetLocation",
  title: "Get Location",
  description: "Gets the user's location",
  params: {},
  infoPlistKeys: {
    NSLocationWhenInUseUsageDescription: "We need your location to complete this action",
  },
  perform: async () => {
    return { lat: 0, lng: 0 };
  },
});
`;

    const result = await ejectIntent(sourceWithPlist, "test.ts");

    expect(result.infoPlist).toBeDefined();
    expect(result.infoPlist!.path).toContain(".plist.fragment.xml");
    expect(result.infoPlist!.content).toContain("NSLocationWhenInUseUsageDescription");
  });

  it("emits entitlements fragment when intent has entitlements", async () => {
    const sourceWithEntitlements = `
import { defineIntent, param } from "@axint/sdk";

export default defineIntent({
  name: "AccessHealth",
  title: "Access Health",
  description: "Accesses health data",
  params: {},
  entitlements: ["com.apple.developer.healthkit"],
  perform: async () => {
    return { ok: true };
  },
});
`;

    const result = await ejectIntent(sourceWithEntitlements, "test.ts");

    expect(result.entitlements).toBeDefined();
    expect(result.entitlements!.path).toContain(".entitlements.fragment.xml");
    expect(result.entitlements!.content).toContain("com.apple.developer.healthkit");
  });

  it("respects outDir option", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts", {
      outDir: "ios/Intents",
    });

    expect(result.swiftFile.path).toContain("ios/Intents/");
    if (result.testFile) {
      expect(result.testFile.path).toContain("ios/Intents/");
    }
  });

  it("throws on compilation failure", async () => {
    const badSource = "const x = 42;";

    await expect(ejectIntent(badSource, "bad.ts")).rejects.toThrow();
  });

  it("test file includes intent title in assertions", async () => {
    const result = await ejectIntent(VALID_SOURCE, "test.ts", {
      includeTests: true,
    });

    expect(result.testFile!.content).toContain('"Send Message"');
  });
});
