import { computeEffectiveAccess } from "../../entities/access/computeEffectiveAccess";
import type { AccessRequest } from "../../entities/access-request/types";
import type { EffectiveAccessResult, ServiceAccessException, ServiceGrant, ServiceModuleEntitlement } from "../../entities/access/types";
import type { Client, TaskManagerWorkspaceManagedBy } from "../../entities/client/types";
import type { EngineWorkflowAccessRequest } from "../../entities/engine-workflow-access-request/types";
import type { Invite } from "../../entities/invite/types";
import { PUBLIC_POOL_CLIENT, isPublicPoolClientId } from "../../entities/public-pool/constants";
import { getServiceLaunchLink } from "../../entities/service/links";
import type { LauncherServiceView, Service } from "../../entities/service/types";
import type { SyncStatus } from "../../entities/sync/types";
import type { TaskerInviteRequest } from "../../entities/tasker-invite-request/types";
import type {
  ClientGroup,
  ClientMembership,
  ClientMembershipRole,
  LauncherGlobalRole,
  LauncherUser,
} from "../../entities/user/types";
import { resolveLauncherRole, resolvePermissions, type LauncherPermissions } from "../lib/permissions";
import {
  mockAuditEvents,
  mockAccessRequests,
  mockEngineWorkflowAccessRequests,
  mockTaskerInviteRequests,
  mockClients,
  mockExceptions,
  mockGrants,
  mockGroups,
  mockInvites,
  mockMemberships,
  mockServices,
  mockSyncStatuses,
  mockUsers,
} from "./mockData";

export interface AuthentikClaimsMock {
  sub: string;
  email: string;
  name: string;
  avatarUrl?: string | null;
  groups: string[];
  activeClientId: string;
}

export interface MeResponse {
  user: Pick<LauncherUser, "id" | "authentikUserId" | "name" | "email" | "avatarUrl">;
  launcherRole: LauncherGlobalRole;
  memberships: Array<{
    clientId: string;
    clientName: string;
    role: ClientMembershipRole;
    status: ClientMembership["status"];
    coreAssistantRole: ClientMembership["coreAssistantRole"];
  }>;
  activeClientId: string;
  permissions: LauncherPermissions;
  mockAuthentikClaims: AuthentikClaimsMock;
}

export interface LauncherData {
  clients: Client[];
  users: LauncherUser[];
  memberships: ClientMembership[];
  groups: ClientGroup[];
  services: Service[];
  grants: ServiceGrant[];
  exceptions: ServiceAccessException[];
  serviceModuleEntitlements: ServiceModuleEntitlement[];
  invites: Invite[];
  accessRequests: AccessRequest[];
  revokedAccounts: RevokedAccount[];
  taskerInviteRequests: TaskerInviteRequest[];
  engineWorkflowAccessRequests: EngineWorkflowAccessRequest[];
  syncStatuses: SyncStatus[];
  auditEvents: typeof mockAuditEvents;
  taskManagerMemberships: TaskManagerMembershipAssignment[];
  taskManagerProjectMemberships: TaskManagerProjectMembershipAssignment[];
  settings: LauncherSettings;
}

export interface RevokedAccount {
  id: string;
  email: string;
  name?: string | null;
  sourceUserId?: string | null;
  authentikUserId?: string | null;
  reason: string;
  revokedByUserId?: string | null;
  revokedByUserEmail?: string | null;
  revokedByUserName?: string | null;
  revokedAt: string;
  createdAt: string;
  updatedAt: string;
}

export interface TaskManagerMembershipAssignment {
  id: string;
  clientId: string;
  userId: string;
  workspaceSlug: string;
  workspaceName?: string | null;
  role: "guest" | "member" | "admin";
  managedBy?: TaskManagerWorkspaceManagedBy;
  planeUserId?: string | null;
  planeRole?: number | null;
  updatedAt: string;
}

export interface TaskManagerProjectMembershipAssignment {
  id: string;
  clientId: string;
  userId: string;
  workspaceSlug: string;
  workspaceName?: string | null;
  projectId: string;
  projectIdentifier?: string | null;
  projectName?: string | null;
  role: "guest" | "member" | "admin";
  managedBy?: TaskManagerWorkspaceManagedBy;
  planeUserId?: string | null;
  planeRole?: number | null;
  updatedAt: string;
}

export interface LauncherSettings {
  brand: {
    logoLinkUrl: string;
  };
  taskManager: {
    workspaceCreationPolicy: TaskManagerWorkspaceCreationPolicy;
  };
}

export type TaskManagerWorkspaceCreationPolicy = "any_authorized_user" | "task_admins_only" | "disabled";

export interface ProfileOption {
  userId: string;
  label: string;
  description: string;
  defaultClientId: string;
}

export interface AccessMatrixCell {
  userId: string;
  serviceId: string;
  effectiveAccess: EffectiveAccessResult;
}

export interface AccessMatrix {
  client: Client;
  users: LauncherUser[];
  groups: ClientGroup[];
  services: Service[];
  cells: AccessMatrixCell[];
}

export const defaultLauncherSettings: LauncherSettings = {
  brand: {
    logoLinkUrl: "/",
  },
  taskManager: {
    workspaceCreationPolicy: "any_authorized_user",
  },
};

export const initialLauncherData: LauncherData = normalizeLauncherData({
  clients: mockClients,
  users: mockUsers,
  memberships: mockMemberships,
  groups: mockGroups,
  services: mockServices,
  grants: mockGrants,
  exceptions: mockExceptions,
  invites: mockInvites,
  accessRequests: mockAccessRequests,
  revokedAccounts: [],
  taskerInviteRequests: mockTaskerInviteRequests,
  engineWorkflowAccessRequests: mockEngineWorkflowAccessRequests,
  syncStatuses: mockSyncStatuses,
  auditEvents: mockAuditEvents,
  settings: defaultLauncherSettings,
});

export function normalizeLauncherSettings(settings?: Partial<LauncherSettings> | null): LauncherSettings {
  const brand =
    typeof settings?.brand === "object" && settings.brand !== null
      ? settings.brand
      : ({} as Partial<LauncherSettings["brand"]>);
  const taskManager =
    typeof settings?.taskManager === "object" && settings.taskManager !== null
      ? settings.taskManager
      : ({} as Partial<LauncherSettings["taskManager"]>);
  const logoLinkUrl = typeof brand.logoLinkUrl === "string" && brand.logoLinkUrl.trim() ? brand.logoLinkUrl.trim() : "/";
  const workspaceCreationPolicy = isTaskManagerWorkspaceCreationPolicy(taskManager.workspaceCreationPolicy)
    ? taskManager.workspaceCreationPolicy
    : defaultLauncherSettings.taskManager.workspaceCreationPolicy;

  return {
    brand: {
      logoLinkUrl,
    },
    taskManager: {
      workspaceCreationPolicy,
    },
  };
}

function isTaskManagerWorkspaceCreationPolicy(value: unknown): value is TaskManagerWorkspaceCreationPolicy {
  return value === "any_authorized_user" || value === "task_admins_only" || value === "disabled";
}

export function normalizeLauncherData(data: Partial<LauncherData> | null | undefined): LauncherData {
  const payload = data ?? {};

  return {
    clients: Array.isArray(payload.clients) ? payload.clients : mockClients,
    users: Array.isArray(payload.users) ? payload.users : mockUsers,
    memberships: Array.isArray(payload.memberships) ? payload.memberships.map(normalizeMembership) : mockMemberships.map(normalizeMembership),
    groups: Array.isArray(payload.groups) ? payload.groups : mockGroups,
    services: Array.isArray(payload.services) ? payload.services : mockServices,
    grants: Array.isArray(payload.grants) ? payload.grants : mockGrants,
    exceptions: Array.isArray(payload.exceptions) ? payload.exceptions : mockExceptions,
    serviceModuleEntitlements: Array.isArray(payload.serviceModuleEntitlements) ? payload.serviceModuleEntitlements : [],
    invites: Array.isArray(payload.invites) ? payload.invites : mockInvites,
    accessRequests: Array.isArray(payload.accessRequests) ? payload.accessRequests : mockAccessRequests,
    revokedAccounts: Array.isArray(payload.revokedAccounts) ? payload.revokedAccounts : [],
    taskerInviteRequests: Array.isArray(payload.taskerInviteRequests) ? payload.taskerInviteRequests : mockTaskerInviteRequests,
    engineWorkflowAccessRequests: Array.isArray(payload.engineWorkflowAccessRequests)
      ? payload.engineWorkflowAccessRequests
      : mockEngineWorkflowAccessRequests,
    syncStatuses: Array.isArray(payload.syncStatuses) ? payload.syncStatuses : mockSyncStatuses,
    auditEvents: Array.isArray(payload.auditEvents) ? payload.auditEvents : mockAuditEvents,
    taskManagerMemberships: Array.isArray(payload.taskManagerMemberships) ? payload.taskManagerMemberships : [],
    taskManagerProjectMemberships: Array.isArray(payload.taskManagerProjectMemberships) ? payload.taskManagerProjectMemberships : [],
    settings: normalizeLauncherSettings(payload.settings),
  };
}

export const profileOptions: ProfileOption[] = [
  {
    userId: "user_root",
    label: "DC Touch",
    description: "NODE.DC superadmin",
    defaultClientId: "client_romashka",
  },
  {
    userId: "user_silver_psih",
    label: "Silver Psy",
    description: "DCTOUCH manager",
    defaultClientId: "client_romashka",
  },
];

export function buildMe(data: LauncherData, userId: string, requestedClientId?: string): MeResponse {
  const user = getUser(data, userId);
  const isRoot = user.id === "user_root";
  const availableMemberships = isRoot
    ? data.clients.map((client) => ({
        clientId: client.id,
        clientName: client.name,
        role: "client_owner" as const,
        status: "active" as const,
        coreAssistantRole: "admin" as const,
      }))
    : data.memberships
        .filter((membership) => membership.userId === user.id)
        .map((membership) => ({
          clientId: membership.clientId,
          clientName: getClient(data, membership.clientId).name,
          role: membership.role,
          status: membership.status,
          coreAssistantRole: normalizeCoreAssistantRole(membership.coreAssistantRole),
        }));

  const fallbackClientId =
    profileOptions.find((option) => option.userId === user.id)?.defaultClientId ??
    availableMemberships[0]?.clientId ??
    PUBLIC_POOL_CLIENT.id;
  const canUseRequestedClient = availableMemberships.some((membership) => membership.clientId === requestedClientId);
  const activeClientId = canUseRequestedClient ? requestedClientId! : fallbackClientId;
  const activeMembership = availableMemberships.find((membership) => membership.clientId === activeClientId);
  const launcherRole = resolveLauncherRole({ isRoot, membershipRole: activeMembership?.role });
  const permissions = resolvePermissions({
    launcherRole,
    membershipStatus: activeMembership?.status,
  });

  return {
    user: {
      id: user.id,
      authentikUserId: user.authentikUserId,
      name: user.name,
      email: user.email,
      avatarUrl: user.avatarUrl,
    },
    launcherRole,
    memberships: availableMemberships,
    activeClientId,
    permissions,
    mockAuthentikClaims: {
      sub: user.authentikUserId ?? user.id,
      email: user.email,
      name: user.name,
      groups: buildMockGroups(data, user.id, activeClientId, launcherRole),
      activeClientId,
    },
  };
}

function normalizeMembership(membership: ClientMembership): ClientMembership {
  return {
    ...membership,
    coreAssistantRole: normalizeCoreAssistantRole(membership.coreAssistantRole, membership.userId === "user_root" ? "admin" : "member"),
  };
}

function normalizeCoreAssistantRole(
  value: ClientMembership["coreAssistantRole"] | null | undefined,
  fallback: NonNullable<ClientMembership["coreAssistantRole"]> = "member"
): NonNullable<ClientMembership["coreAssistantRole"]> {
  if (value === "blocked" || value === "member" || value === "admin") return value;
  return fallback;
}

export function buildLauncherServices(data: LauncherData, userId: string, activeClientId: string): LauncherServiceView[] {
  const me = buildMe(data, userId, activeClientId);
  const user = getUser(data, userId);
  const client = getClient(data, activeClientId);
  const membership = getRuntimeMembership(data, user.id, activeClientId, me.launcherRole === "root_admin");
  const userGroups = getUserGroups(data, user.id, activeClientId);
  const isRoot = me.launcherRole === "root_admin";

  return data.services
    .slice()
    .sort((a, b) => a.order - b.order)
    .map((service) => {
      const effectiveAccess = computeEffectiveAccess({
        client,
        user,
        membership,
        userGroups,
        service,
        grants: data.grants,
        exceptions: data.exceptions,
      });

      return {
        id: service.id,
        slug: service.slug,
        title: service.title,
        subtitle: service.subtitle,
        description: service.description,
        fullDescription: service.fullDescription,
        status: service.status,
        userAccess: effectiveAccess.allowed ? ("allowed" as const) : ("denied" as const),
        appRole: effectiveAccess.appRole,
        openUrl: effectiveAccess.openEnabled ? getServiceLaunchLink(service) || null : null,
        accentColor: service.accentColor,
        media: {
          icon: service.iconUrl,
          thumbnail: service.coverImageUrl,
          coverImage: service.coverImageUrl,
          coverKind: service.coverMediaKind,
          coverSource: service.coverMediaSource,
          coverFileName: service.coverMediaFileName,
          previewVideo: service.previewVideoUrl,
          ambientVideo: service.ambientVideoUrl,
          ambientKind: service.ambientMediaKind,
          ambientSource: service.ambientMediaSource,
          ambientFileName: service.ambientMediaFileName,
          fallbackGradient: service.fallbackGradient,
        },
        effectiveAccess,
      };
    })
    .filter((service) => isRoot || service.status !== "hidden");
}

export function buildAccessMatrix(data: LauncherData, clientId: string, includeAllServices: boolean): AccessMatrix {
  const client = getClient(data, clientId);
  const memberships = data.memberships.filter((membership) => membership.clientId === clientId);
  const users = memberships.map((membership) => getUser(data, membership.userId));
  const groups = data.groups.filter((group) => group.clientId === clientId);
  const clientServiceIds = new Set(
    data.grants
      .filter((grant) => grant.targetType === "client" && grant.targetId === clientId && grant.status === "active")
      .map((grant) => grant.serviceId)
  );
  const services = data.services
    .filter((service) => includeAllServices || clientServiceIds.has(service.id) || service.status === "active")
    .sort((a, b) => a.order - b.order);
  const cells = users.flatMap((user) => {
    const membership = memberships.find((item) => item.userId === user.id) ?? getRuntimeMembership(data, user.id, clientId);
    const userGroups = getUserGroups(data, user.id, clientId);

    return services.map((service) => ({
      userId: user.id,
      serviceId: service.id,
      effectiveAccess: computeEffectiveAccess({
        client,
        user,
        membership,
        userGroups,
        service,
        grants: data.grants,
        exceptions: data.exceptions,
      }),
    }));
  });

  return { client, users, groups, services, cells };
}

export function getClient(data: LauncherData, clientId: string): Client {
  if (isPublicPoolClientId(clientId)) {
    return PUBLIC_POOL_CLIENT;
  }

  const client = data.clients.find((item) => item.id === clientId);
  if (!client) throw new Error(`Unknown client: ${clientId}`);
  return client;
}

export function getUser(data: LauncherData, userId: string): LauncherUser {
  const user = data.users.find((item) => item.id === userId);
  if (!user) throw new Error(`Unknown user: ${userId}`);
  return user;
}

export function getService(data: LauncherData, serviceId: string): Service {
  const service = data.services.find((item) => item.id === serviceId);
  if (!service) throw new Error(`Unknown service: ${serviceId}`);
  return service;
}

export function getClientUsers(data: LauncherData, clientId: string): LauncherUser[] {
  const userIds = new Set(data.memberships.filter((membership) => membership.clientId === clientId).map((item) => item.userId));
  return data.users.filter((user) => userIds.has(user.id));
}

export function getUserGroups(data: LauncherData, userId: string, clientId: string): ClientGroup[] {
  return data.groups.filter((group) => group.clientId === clientId && group.memberIds.includes(userId));
}

export function getRuntimeMembership(
  data: LauncherData,
  userId: string,
  clientId: string,
  allowVirtualRoot = false
): ClientMembership {
  const membership = data.memberships.find((item) => item.userId === userId && item.clientId === clientId);
  if (membership) return membership;

  if (allowVirtualRoot) {
    return {
      id: `virtual_root_${clientId}`,
      clientId,
      userId,
      role: "client_owner",
      status: "active",
      createdAt: "2026-05-01T09:00:00Z",
      updatedAt: "2026-05-01T09:00:00Z",
    };
  }

  return {
    id: `missing_${clientId}_${userId}`,
    clientId,
    userId,
    role: "member",
    status: "disabled",
    createdAt: "2026-05-01T09:00:00Z",
    updatedAt: "2026-05-01T09:00:00Z",
  };
}

function buildMockGroups(
  data: LauncherData,
  userId: string,
  activeClientId: string,
  launcherRole: LauncherGlobalRole
): string[] {
  const groups = getUserGroups(data, userId, activeClientId).map((group) => `client:${activeClientId}:group:${group.name}`);
  return [`launcher:${launcherRole}`, `client:${activeClientId}`, ...groups];
}
