import { beforeEach, describe, expect, it } from "vitest"
import { mount } from "@vue/test-utils"
import { createPinia, setActivePinia } from "pinia"
import DependencyListBuilder from "./DependencyListBuilder.vue"
import {
  __resetDependencyListBuilderIdCounter,
  useDependencyListBuilderStore,
  type DependencyListBuilderSchema,
} from "@/stores/dependencyListBuilderStore"

const BUILDER_ID = "dep-test"

describe("DependencyListBuilder", () => {
  beforeEach(() => {
    setActivePinia(createPinia())
    __resetDependencyListBuilderIdCounter()
  })

  it("renders the three-pane layout", () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    expect(
      wrapper.find("[data-testid='dependency-list-builder']").exists(),
    ).toBe(true)
    expect(
      wrapper
        .find("[data-testid='dependency-list-builder-palette']")
        .exists(),
    ).toBe(true)
    expect(
      wrapper
        .find("[data-testid='dependency-list-builder-canvas']")
        .exists(),
    ).toBe(true)
    expect(
      wrapper
        .find("[data-testid='dependency-list-builder-inspector']")
        .exists(),
    ).toBe(true)
  })

  it("shows an empty-state hint when there are no rules", () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    expect(
      wrapper
        .find("[data-testid='dependency-list-builder-canvas-empty']")
        .exists(),
    ).toBe(true)
  })

  it("lists every rule template in the palette", () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    for (const t of ["blank", "show-field", "hide-field", "set-value"]) {
      expect(
        wrapper
          .find(`[data-testid='dependency-list-builder-palette-${t}']`)
          .exists(),
      ).toBe(true)
    }
  })

  it("adding a rule selects it and shows the inspector", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-show-field']")
      .trigger("click")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules).toHaveLength(1)
    expect(store.getSchema(BUILDER_ID).rules[0]!.name).toBe("Show field")
    expect(
      wrapper
        .find("[data-testid='dependency-list-builder-inspector-fields']")
        .exists(),
    ).toBe(true)
  })

  it("editing the name patches the schema", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-blank']")
      .trigger("click")
    await wrapper
      .find("[data-testid='dependency-list-builder-inspector-name']")
      .setValue("Custom rule name")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules[0]!.name).toBe(
      "Custom rule name",
    )
  })

  it("adds a condition via the inspector", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-blank']")
      .trigger("click")
    await wrapper
      .find("[data-testid='dependency-list-builder-add-condition']")
      .trigger("click")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules[0]!.conditions).toHaveLength(1)
  })

  it("removes a condition", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-show-field']")
      .trigger("click")
    // show-field template ships with 1 condition.
    await wrapper
      .find("[data-testid='dependency-list-builder-condition-remove-0']")
      .trigger("click")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules[0]!.conditions).toHaveLength(0)
  })

  it("adds and removes an action", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-blank']")
      .trigger("click")
    await wrapper
      .find("[data-testid='dependency-list-builder-add-action']")
      .trigger("click")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules[0]!.actions).toHaveLength(1)

    await wrapper
      .find("[data-testid='dependency-list-builder-action-remove-0']")
      .trigger("click")
    expect(store.getSchema(BUILDER_ID).rules[0]!.actions).toHaveLength(0)
  })

  it("removes the selected rule", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-blank']")
      .trigger("click")
    await wrapper
      .find("[data-testid='dependency-list-builder-remove']")
      .trigger("click")

    const store = useDependencyListBuilderStore()
    expect(store.getSchema(BUILDER_ID).rules).toHaveLength(0)
  })

  it("loads an existing schema from modelValue on mount", () => {
    const seed: DependencyListBuilderSchema = {
      rules: [
        {
          id: "seed-rule",
          name: "Seeded rule",
          enabled: true,
          conditions: [
            { field: "country", operator: "equals", value: "US" },
          ],
          conditionsLogic: "AND",
          actions: [{ type: "show", target: "state" }],
        },
      ],
    }
    mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID, modelValue: seed },
    })

    const store = useDependencyListBuilderStore()
    const rules = store.getSchema(BUILDER_ID).rules
    expect(rules).toHaveLength(1)
    expect(rules[0]!.name).toBe("Seeded rule")
    expect(rules[0]!.conditions[0]!.field).toBe("country")
  })

  it("emits update:modelValue on mutation", async () => {
    const wrapper = mount(DependencyListBuilder, {
      props: { builderId: BUILDER_ID },
    })
    await wrapper
      .find("[data-testid='dependency-list-builder-palette-blank']")
      .trigger("click")
    await wrapper.vm.$nextTick()

    const emitted = wrapper.emitted("update:modelValue")
    expect(emitted).toBeTruthy()
    const last = emitted![emitted!.length - 1] as unknown[]
    const value = last[0] as DependencyListBuilderSchema
    expect(value.rules).toHaveLength(1)
  })
})
