import { describe, it, expect, vi, beforeEach } from "vitest";
import { setActivePinia, createPinia } from "pinia";
import { useDevicesStore } from "../devices.js";

vi.mock("../../api/modules/devices.js", () => ({
  devicesApi: {
    list: vi.fn(),
    status: vi.fn(),
    reboot: vi.fn(),
    resetup: vi.fn(),
    reset: vi.fn(),
  },
}));

import { devicesApi } from "../../api/modules/devices.js";

describe("useDevicesStore", () => {
  beforeEach(() => {
    setActivePinia(createPinia());
    vi.clearAllMocks();
  });

  describe("loadDevices", () => {
    it("sets devices on success", async () => {
      devicesApi.list.mockResolvedValue({
        ok: true,
        data: { data: { devices: [{ id: 1, name: "Relay" }] } },
      });

      const store = useDevicesStore();
      await store.loadDevices();

      expect(store.devices).toEqual([{ id: 1, name: "Relay" }]);
      expect(store.isLoading).toBe(false);
      expect(store.error).toBeNull();
      expect(store.lastLoadedAt).not.toBeNull();
    });

    it("sets error on failure", async () => {
      devicesApi.list.mockResolvedValue({
        ok: false,
        error: { message: "Failed" },
      });

      const store = useDevicesStore();
      await store.loadDevices();

      expect(store.error).toEqual({ message: "Failed" });
      expect(store.isLoading).toBe(false);
    });
  });

  describe("setDeviceState", () => {
    it("stores state by device id", () => {
      const store = useDevicesStore();
      store.devices = [{ id: 1, connection_status: "active" }];

      store.setDeviceState(store.devices[0], { status: "loading", message: "Loading" });

      expect(store.stateByDeviceId["1"]).toMatchObject({
        deviceId: "1",
        status: "loading",
        message: "Loading",
        connectionStatus: "active",
      });
    });

    it("does nothing for missing device id", () => {
      const store = useDevicesStore();
      store.setDeviceState(null, { status: "loading" });

      expect(store.stateByDeviceId).toEqual({});
    });
  });

  describe("loadDeviceStates", () => {
    it("marks lost devices as skipped", async () => {
      devicesApi.status.mockResolvedValue({ ok: true, data: {} });

      const store = useDevicesStore();
      store.devices = [{ id: 1, connection_status: "lost" }];

      await store.loadDeviceStates();

      expect(store.stateByDeviceId["1"].status).toBe("skipped");
      expect(store.stateByDeviceId["1"].message).toBe("Connection lost");
      expect(devicesApi.status).not.toHaveBeenCalled();
    });

    it("fetches status for active devices", async () => {
      devicesApi.status.mockResolvedValue({
        ok: true,
        data: { data: { device: { device_response: { status: "ok" } } } },
      });

      const store = useDevicesStore();
      store.devices = [{ id: 1, connection_status: "active" }];

      await store.loadDeviceStates();

      expect(devicesApi.status).toHaveBeenCalledWith(1);
      expect(store.stateByDeviceId["1"].status).toBe("ready");
      expect(store.stateByDeviceId["1"].message).toBe("ok");
    });

    it("marks errored status responses", async () => {
      devicesApi.status.mockResolvedValue({
        ok: false,
        error: { message: "Timeout", raw: {} },
      });

      const store = useDevicesStore();
      store.devices = [{ id: 1, connection_status: "active" }];

      await store.loadDeviceStates();

      expect(store.stateByDeviceId["1"].status).toBe("error");
      expect(store.stateByDeviceId["1"].message).toBe("Timeout");
    });
  });

  describe("rebootDevice", () => {
    it("calls API and clears rebooting state after", async () => {
      devicesApi.reboot.mockResolvedValue({ ok: true });

      const store = useDevicesStore();
      expect(store.isRebooting(1)).toBe(false);

      await store.rebootDevice(1);

      expect(store.isRebooting(1)).toBe(false);
      expect(devicesApi.reboot).toHaveBeenCalledWith(1);
    });

    it("tracks rebooting id in state", () => {
      const store = useDevicesStore();
      store.rebootingIds.add("1");

      expect(store.rebootingIds.has("1")).toBe(true);
      expect(store.rebootingIds.has("2")).toBe(false);
    });
  });
});
