import Cookies from "js-cookie";

function getCookieExpiresDays(): number {
  if (typeof window === "undefined") return 1;
  try {
    const rememberMe = localStorage.getItem("rememberMe") === "true";
    return rememberMe ? 15 : 1;
  } catch {
    return 1;
  }
}

const isHttps =
  typeof window !== "undefined" && window.location.protocol === "https:";

function removeCookieCompletely(name: string) {
  if (typeof document === "undefined") return;

  const paths = ["/", ""];
  const samesites: Array<"strict" | "lax" | "none" | undefined> = [
    "strict",
    "lax",
    undefined,
  ];
  const secures = [true, false];

  for (const path of paths) {
    for (const secure of secures) {
      for (const sameSite of samesites) {
        try {
          Cookies.remove(name, { path, secure, sameSite });
        } catch {
          // ignore
        }
      }
    }
  }

  const pastDate = "Thu, 01 Jan 1970 00:00:00 GMT";
  const expireStrings = [
    `${name}=; path=/; expires=${pastDate}; max-age=0`,
    `${name}=; path=/; expires=${pastDate}; max-age=0; SameSite=Strict`,
    `${name}=; path=/; expires=${pastDate}; max-age=0; SameSite=Strict; Secure`,
    `${name}=; path=/; expires=${pastDate}; max-age=0; SameSite=Lax`,
    `${name}=; path=/; expires=${pastDate}; max-age=0; SameSite=Lax; Secure`,
    `${name}=; expires=${pastDate}; max-age=0`,
  ];

  try {
    const domain = window.location.hostname;
    const domainParts = domain.split(".");
    if (domainParts.length > 1) {
      expireStrings.push(
        `${name}=; path=/; domain=${domain}; expires=${pastDate}; max-age=0`
      );
      expireStrings.push(
        `${name}=; path=/; domain=.${domain}; expires=${pastDate}; max-age=0`
      );
    }
  } catch {
    // ignore
  }

  expireStrings.forEach((str) => {
    try {
      document.cookie = str;
    } catch {
      // ignore
    }
  });
}

interface Backend {
  get(k: string): string | null;
  set(k: string, v: string): void;
  remove(k: string): void;
}

const localStore: Backend = {
  get: (k) => localStorage.getItem(k),
  set: (k, v) => localStorage.setItem(k, v),
  remove: (k) => localStorage.removeItem(k),
};

const cookieStore: Backend = {
  get: (k) => Cookies.get(k) ?? null,
  set: (k, v) =>
    Cookies.set(k, v, {
      path: "/",
      secure: isHttps,
      sameSite: "strict",
      expires: getCookieExpiresDays(),
    }),
  remove: (k) => removeCookieCompletely(k),
};

const AUTH_KEY_NAMES = [
  "auth-token",
  "refresh-token",
  "auth-user",
  "profile-id",
  "current-profile",
];

const KNOWN_PREFIXES = ["ema-backoffice", "ema-portal", "ema-auth", ""];

let _prefix = "ema-auth";
let backend: Backend = localStore;

export function configureAuthStorage(prefix: string, useCookies = false) {
  _prefix = prefix;
  backend = useCookies ? cookieStore : localStore;
  if (useCookies) {
    // drop pre-migration localStorage leftovers so tokens live in cookies only
    AUTH_KEY_NAMES.forEach((k) => localStorage.removeItem(`${prefix}-${k}`));
  }
}

function key(k: string) {
  return `${_prefix}-${k}`;
}

export const authStorage = {
  getToken: () => backend.get(key("auth-token")) ?? undefined,
  setToken: (token: string) => backend.set(key("auth-token"), token),
  getRefreshToken: () => backend.get(key("refresh-token")) ?? undefined,
  setRefreshToken: (t: string) => backend.set(key("refresh-token"), t),
  getUser: <T = unknown>(): T | null => {
    try {
      return JSON.parse(backend.get(key("auth-user")) ?? "null") as T | null;
    } catch {
      return null;
    }
  },
  setUser: <T>(u: T) => backend.set(key("auth-user"), JSON.stringify(u)),
  getProfileId: () => backend.get(key("profile-id")) ?? undefined,
  setProfileId: (id: string) => backend.set(key("profile-id"), id),
  getProfile: <T = unknown>(): T | null => {
    try {
      return JSON.parse(
        backend.get(key("current-profile")) ?? "null",
      ) as T | null;
    } catch {
      return null;
    }
  },
  setProfile: <T>(p: T) =>
    backend.set(key("current-profile"), JSON.stringify(p)),
  removeProfile: () => backend.remove(key("current-profile")),
  clear: () => {
    const prefixes = Array.from(new Set([_prefix, ...KNOWN_PREFIXES]));
    prefixes.forEach((p) => {
      AUTH_KEY_NAMES.forEach((k) => {
        const fullKey = p ? `${p}-${k}` : k;
        removeCookieCompletely(fullKey);
        try {
          localStorage.removeItem(fullKey);
        } catch {
          // ignore
        }
      });
    });

    try {
      localStorage.removeItem("rememberMe");
    } catch {
      // ignore
    }

    try {
      if (typeof Cookies !== "undefined") {
        const allCookies = Cookies.get();
        if (allCookies) {
          Object.keys(allCookies).forEach((name) => {
            removeCookieCompletely(name);
          });
        }
      }
    } catch {
      // ignore
    }
  },
};
