import { describe, expect, it } from "vitest";
import { computeEffectiveAccess } from "./computeEffectiveAccess";
import type { Client } from "../client/types";
import type { Service } from "../service/types";
import type { ClientGroup, ClientMembership, LauncherUser } from "../user/types";
import type { ServiceAccessException, ServiceGrant } from "./types";

const client: Client = {
  id: "client_a",
  type: "company",
  name: "ООО Тест",
  status: "active",
  createdAt: "2026-04-01T00:00:00Z",
  updatedAt: "2026-04-01T00:00:00Z",
};

const user: LauncherUser = {
  id: "user_a",
  name: "Пользователь",
  email: "user@example.ru",
  globalStatus: "active",
  createdAt: "2026-04-01T00:00:00Z",
  updatedAt: "2026-04-01T00:00:00Z",
};

const membership: ClientMembership = {
  id: "membership_a",
  clientId: client.id,
  userId: user.id,
  role: "member",
  status: "active",
  createdAt: "2026-04-01T00:00:00Z",
  updatedAt: "2026-04-01T00:00:00Z",
};

const group: ClientGroup = {
  id: "group_a",
  clientId: client.id,
  name: "Группа",
  memberIds: [user.id],
  createdAt: "2026-04-01T00:00:00Z",
  updatedAt: "2026-04-01T00:00:00Z",
};

const service: Service = {
  id: "service_a",
  slug: "service-a",
  title: "Service A",
  description: "Demo service",
  url: "https://example.ru",
  status: "active",
  order: 1,
  createdAt: "2026-04-01T00:00:00Z",
  updatedAt: "2026-04-01T00:00:00Z",
};

const baseInput = {
  client,
  user,
  membership,
  userGroups: [group],
  service,
  grants: [] as ServiceGrant[],
  exceptions: [] as ServiceAccessException[],
};

describe("computeEffectiveAccess", () => {
  it("returns false when client is suspended", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      client: { ...client, status: "suspended" },
    });

    expect(result.allowed).toBe(false);
    expect(result.reason).toContain("Клиент");
  });

  it("returns false when user is blocked", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      user: { ...user, globalStatus: "blocked" },
    });

    expect(result.allowed).toBe(false);
    expect(result.reason).toContain("Пользователь");
  });

  it("returns false when no grant exists", () => {
    const result = computeEffectiveAccess(baseInput);

    expect(result.allowed).toBe(false);
    expect(result.visible).toBe(false);
  });

  it("returns true from client grant", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      grants: [grant("client", client.id)],
    });

    expect(result.allowed).toBe(true);
    expect(result.source).toBe("client");
  });

  it("returns true from group grant", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      grants: [grant("group", group.id)],
    });

    expect(result.allowed).toBe(true);
    expect(result.source).toBe("group");
  });

  it("returns true from user grant", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      grants: [grant("user", user.id)],
    });

    expect(result.allowed).toBe(true);
    expect(result.source).toBe("user");
  });

  it("deny exception overrides user grant", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      grants: [grant("user", user.id)],
      exceptions: [deny()],
    });

    expect(result.allowed).toBe(false);
    expect(result.source).toBe("exception");
  });

  it("maintenance service is visible but openEnabled is false", () => {
    const result = computeEffectiveAccess({
      ...baseInput,
      service: { ...service, status: "maintenance" },
      grants: [grant("client", client.id)],
    });

    expect(result.visible).toBe(true);
    expect(result.openEnabled).toBe(false);
  });
});

function grant(targetType: ServiceGrant["targetType"], targetId: string): ServiceGrant {
  return {
    id: `grant_${targetType}`,
    serviceId: service.id,
    targetType,
    targetId,
    appRole: "member",
    status: "active",
    createdAt: "2026-04-01T00:00:00Z",
    updatedAt: "2026-04-01T00:00:00Z",
  };
}

function deny(): ServiceAccessException {
  return {
    id: "exception_deny",
    serviceId: service.id,
    userId: user.id,
    type: "deny",
    reason: "Тестовый deny",
    createdAt: "2026-04-01T00:00:00Z",
    updatedAt: "2026-04-01T00:00:00Z",
  };
}
