import { defineStore } from "pinia";

export type AuthScope = "TENANT" | "PLATFORM";

export type StoredAppearance = {
  themeMode?: string;
  density?: string;
  themeScheme?: string;
};

export type AuthPayload = {
  token?: string;
  permissions?: string[];
  roles?: string[];
  userId?: number | string | null;
  phone?: string;
  tenantId?: number | string | null;
  userName?: string;
  tenantName?: string;
  tenantCode?: string;
  tenant?: {
    logoUrl?: string;
    [key: string]: unknown;
  } | null;
  scope?: AuthScope;
  appearance?: StoredAppearance | null;
};

type TenantProfilePatch = {
  tenantName?: string | null;
  logoUrl?: string | null;
};

type AuthState = {
  token: string;
  permissions: string[];
  roles: string[];
  userId: number | null;
  phone: string;
  tenantId: number | null;
  userName: string;
  tenantName: string;
  tenantCode: string;
  tenantInfo: Record<string, unknown> | null;
  tenantLogoUrl: string;
  scope: AuthScope;
  appearance: StoredAppearance;
  authVersion: string;
  tenantContextVersion: string;
};

const AUTH_EVENT_NAME = "auth:token-updated";

type TenantContextSnapshot = {
  scope: AuthScope;
  tenantId: number | null;
  userId: number | null;
};

const parseNumber = (raw: string | null): number | null => {
  if (!raw) {
    return null;
  }
  const value = Number(raw);
  return Number.isFinite(value) ? value : null;
};

const parseStringArray = (raw: string | null): string[] => {
  if (!raw) {
    return [];
  }
  try {
    const parsed = JSON.parse(raw);
    return Array.isArray(parsed) ? parsed.map((item) => String(item)) : [];
  } catch (_e) {
    return [];
  }
};

const parseObject = (raw: string | null): Record<string, unknown> | null => {
  if (!raw) {
    return null;
  }
  try {
    const parsed = JSON.parse(raw);
    return parsed && typeof parsed === "object" ? parsed : null;
  } catch (_e) {
    return null;
  }
};

const readStoredScope = (): AuthScope => (localStorage.getItem("scope") === "PLATFORM" ? "PLATFORM" : "TENANT");

const readStoredTenantContext = (): TenantContextSnapshot => ({
  scope: readStoredScope(),
  tenantId: parseNumber(localStorage.getItem("tenantId")),
  userId: parseNumber(localStorage.getItem("userId")),
});

const normalizeTenantContext = (payload: AuthPayload | null | undefined): TenantContextSnapshot => {
  const data = payload || {};
  const nextTenantId = data.tenantId === undefined ? null : parseNumber(String(data.tenantId ?? ""));
  const nextUserId = data.userId === undefined ? null : parseNumber(String(data.userId ?? ""));
  return {
    scope: data.scope === "PLATFORM" ? "PLATFORM" : "TENANT",
    tenantId: nextTenantId,
    userId: nextUserId,
  };
};

const isSameTenantContext = (left: TenantContextSnapshot, right: TenantContextSnapshot): boolean =>
  left.scope === right.scope && left.tenantId === right.tenantId && left.userId === right.userId;

const nextVersion = (): string => String(Date.now());

const readStoredAppearance = (): StoredAppearance => {
  const raw = localStorage.getItem("appearance");
  const fallbackThemeMode = String(localStorage.getItem("themeMode") || "").trim();
  const fallbackDensity = String(localStorage.getItem("density") || "").trim();
  const fallbackThemeScheme = String(localStorage.getItem("themeScheme") || "").trim();
  if (!raw) {
    return {
      themeMode: fallbackThemeMode,
      density: fallbackDensity,
      themeScheme: fallbackThemeScheme,
    };
  }
  try {
    const parsed = JSON.parse(raw) || {};
    return {
      themeMode: String(parsed?.themeMode || fallbackThemeMode).trim(),
      density: String(parsed?.density || fallbackDensity).trim(),
      themeScheme: String(parsed?.themeScheme || fallbackThemeScheme).trim(),
    };
  } catch (_e) {
    return {
      themeMode: fallbackThemeMode,
      density: fallbackDensity,
      themeScheme: fallbackThemeScheme,
    };
  }
};

const readAuthStateFromStorage = (): AuthState => {
  const tenantInfo = parseObject(localStorage.getItem("tenantInfo"));
  const tenantLogoUrl = String(localStorage.getItem("tenantLogoUrl") || "").trim();
  const authVersion = String(localStorage.getItem("authVersion") || "").trim();
  return {
    token: String(localStorage.getItem("token") || "").trim(),
    permissions: parseStringArray(localStorage.getItem("permissions")),
    roles: parseStringArray(localStorage.getItem("roles")),
    userId: parseNumber(localStorage.getItem("userId")),
    phone: String(localStorage.getItem("phone") || "").trim(),
    tenantId: parseNumber(localStorage.getItem("tenantId")),
    userName: String(localStorage.getItem("userName") || "").trim(),
    tenantName: String(localStorage.getItem("tenantName") || "").trim(),
    tenantCode: String(localStorage.getItem("tenantCode") || "").trim(),
    tenantInfo,
    tenantLogoUrl,
    scope: readStoredScope(),
    appearance: readStoredAppearance(),
    authVersion,
    tenantContextVersion: String(localStorage.getItem("tenantContextVersion") || authVersion || "").trim(),
  };
};

const applyAuthState = (target: AuthState, source: AuthState) => {
  target.token = source.token;
  target.permissions = source.permissions;
  target.roles = source.roles;
  target.userId = source.userId;
  target.phone = source.phone;
  target.tenantId = source.tenantId;
  target.userName = source.userName;
  target.tenantName = source.tenantName;
  target.tenantCode = source.tenantCode;
  target.tenantInfo = source.tenantInfo;
  target.tenantLogoUrl = source.tenantLogoUrl;
  target.scope = source.scope;
  target.appearance = source.appearance;
  target.authVersion = source.authVersion;
  target.tenantContextVersion = source.tenantContextVersion;
};

const dispatchAuthUpdated = () => {
  if (typeof window !== "undefined") {
    window.dispatchEvent(new CustomEvent(AUTH_EVENT_NAME));
  }
};

export const useAuthStore = defineStore("auth", {
  state: (): AuthState => readAuthStateFromStorage(),
  getters: {
    hasPermission: (state) => (code: string): boolean => state.permissions.indexOf(code) >= 0,
    currentTenantLogo: (state): string => {
      const logoFromInfo = String(state.tenantInfo?.logoUrl || "").trim();
      return logoFromInfo || state.tenantLogoUrl;
    },
  },
  actions: {
    syncFromStorage() {
      applyAuthState(this, readAuthStateFromStorage());
    },
    saveAuthPayload(payload: AuthPayload | null | undefined) {
      const data = payload || {};
      const previousTenantContext = readStoredTenantContext();
      const nextTenantContext = normalizeTenantContext(data);
      const authVersion = nextVersion();
      const tenantContextVersion = isSameTenantContext(previousTenantContext, nextTenantContext)
        ? String(localStorage.getItem("tenantContextVersion") || authVersion)
        : authVersion;
      localStorage.setItem("token", String(data.token || ""));
      localStorage.setItem("userId", String(data.userId || ""));
      localStorage.setItem("phone", String(data.phone || ""));
      localStorage.setItem("tenantId", String(data.tenantId || ""));
      localStorage.setItem("userName", String(data.userName || ""));
      localStorage.setItem("tenantName", String(data.tenantName || ""));
      localStorage.setItem("tenantCode", String(data.tenantCode || ""));
      localStorage.setItem("tenantLogoUrl", String(data.tenant?.logoUrl || ""));
      localStorage.setItem("tenantInfo", JSON.stringify(data.tenant || {}));
      localStorage.setItem("scope", data.scope === "PLATFORM" ? "PLATFORM" : "TENANT");
      localStorage.setItem("permissions", JSON.stringify(Array.isArray(data.permissions) ? data.permissions : []));
      localStorage.setItem("roles", JSON.stringify(Array.isArray(data.roles) ? data.roles : []));
      localStorage.setItem("appearance", JSON.stringify(data.appearance || {}));
      localStorage.setItem("themeMode", String(data.appearance?.themeMode || ""));
      localStorage.setItem("density", String(data.appearance?.density || ""));
      localStorage.setItem("themeScheme", String(data.appearance?.themeScheme || ""));
      localStorage.setItem("authVersion", authVersion);
      localStorage.setItem("tenantContextVersion", tenantContextVersion);
      this.syncFromStorage();
      dispatchAuthUpdated();
    },
    updateTenantProfile(patch: TenantProfilePatch | null | undefined) {
      const data = patch || {};
      const nextTenantName = data.tenantName === undefined ? this.tenantName : String(data.tenantName || "").trim();
      const nextLogoUrl = data.logoUrl === undefined ? this.currentTenantLogo : String(data.logoUrl || "").trim();
      const nextTenantInfo = {
        ...(this.tenantInfo || {}),
        logoUrl: nextLogoUrl,
      };
      localStorage.setItem("tenantName", nextTenantName);
      localStorage.setItem("tenantLogoUrl", nextLogoUrl);
      localStorage.setItem("tenantInfo", JSON.stringify(nextTenantInfo));
      this.tenantName = nextTenantName;
      this.tenantLogoUrl = nextLogoUrl;
      this.tenantInfo = nextTenantInfo;
      dispatchAuthUpdated();
    },
    clearAuthStorage() {
      const clearedVersion = nextVersion();
      localStorage.removeItem("token");
      localStorage.removeItem("permissions");
      localStorage.removeItem("roles");
      localStorage.removeItem("userId");
      localStorage.removeItem("phone");
      localStorage.removeItem("tenantId");
      localStorage.removeItem("userName");
      localStorage.removeItem("tenantName");
      localStorage.removeItem("tenantLogoUrl");
      localStorage.removeItem("tenantInfo");
      localStorage.removeItem("tenantCode");
      localStorage.removeItem("scope");
      localStorage.removeItem("appearance");
      localStorage.removeItem("themeMode");
      localStorage.removeItem("density");
      localStorage.removeItem("themeScheme");
      localStorage.setItem("authVersion", clearedVersion);
      localStorage.setItem("tenantContextVersion", clearedVersion);
      this.syncFromStorage();
      dispatchAuthUpdated();
    },
  },
});
