import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';
const { proxy } = require('valtio');

const BASE_URL_KEY = 'sub2api_base_url';
const ADMIN_KEY_KEY = 'sub2api_admin_api_key';
const ACCOUNTS_KEY = 'sub2api_accounts';
const ACTIVE_ACCOUNT_ID_KEY = 'sub2api_active_account_id';
const IS_WEB = Platform.OS === 'web';

export type AdminAccountProfile = {
  id: string;
  label: string;
  baseUrl: string;
  adminApiKey: string;
  updatedAt: string;
  enabled?: boolean;
};

function createAccountId() {
  return `acct_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
}

function getAccountLabel(baseUrl: string) {
  try {
    const url = new URL(baseUrl);
    return url.host || baseUrl;
  } catch {
    return baseUrl;
  }
}

function normalizeConfig(input: { baseUrl: string; adminApiKey: string }) {
  return {
    baseUrl: input.baseUrl.trim().replace(/\/$/, ''),
    adminApiKey: input.adminApiKey.trim(),
  };
}

function sortAccounts(accounts: AdminAccountProfile[]) {
  return [...accounts].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
}

function normalizeAccount(account: AdminAccountProfile): AdminAccountProfile {
  return {
    ...account,
    adminApiKey: account.adminApiKey ?? '',
    enabled: account.enabled ?? true,
  };
}

function sanitizeAccountsForWeb(accounts: AdminAccountProfile[]) {
  if (!IS_WEB) {
    return accounts;
  }

  return accounts.map((account) => ({
    ...account,
    adminApiKey: '',
  }));
}

function persistAdminApiKey(value: string) {
  if (IS_WEB) {
    return deleteItem(ADMIN_KEY_KEY);
  }

  return setItem(ADMIN_KEY_KEY, value);
}

function persistAccounts(accounts: AdminAccountProfile[]) {
  return setItem(ACCOUNTS_KEY, JSON.stringify(sanitizeAccountsForWeb(accounts)));
}

export function hasAuthenticatedAdminSession(config: { baseUrl: string; adminApiKey: string }) {
  const hasBaseUrl = Boolean(config.baseUrl.trim());

  if (!hasBaseUrl) {
    return false;
  }

  if (!IS_WEB) {
    return true;
  }

  return Boolean(config.adminApiKey.trim());
}

function getNextActiveAccount(accounts: AdminAccountProfile[], activeAccountId?: string) {
  const enabledAccounts = accounts.filter((account) => account.enabled !== false);

  if (activeAccountId) {
    const preferred = enabledAccounts.find((account) => account.id === activeAccountId);
    if (preferred) {
      return preferred;
    }
  }

  return enabledAccounts[0];
}

export function getDefaultAdminConfig() {
  return {
    baseUrl: '',
    adminApiKey: '',
  };
}

async function getItem(key: string) {
  try {
    if (Platform.OS === 'web') {
      if (typeof localStorage === 'undefined') {
        return null;
      }

      return localStorage.getItem(key);
    }

    return await SecureStore.getItemAsync(key);
  } catch {
    return null;
  }
}

async function setItem(key: string, value: string) {
  try {
    if (Platform.OS === 'web') {
      if (typeof localStorage !== 'undefined') {
        localStorage.setItem(key, value);
      }

      return;
    }

    await SecureStore.setItemAsync(key, value);
  } catch {
    return;
  }
}

async function deleteItem(key: string) {
  try {
    if (Platform.OS === 'web') {
      if (typeof localStorage !== 'undefined') {
        localStorage.removeItem(key);
      }

      return;
    }

    await SecureStore.deleteItemAsync(key);
  } catch {
    return;
  }
}

export const adminConfigState = proxy({
  ...getDefaultAdminConfig(),
  accounts: [] as AdminAccountProfile[],
  activeAccountId: '',
  hydrated: false,
  saving: false,
});

export async function hydrateAdminConfig() {
  const defaults = getDefaultAdminConfig();

  try {
    const [baseUrl, adminApiKey, rawAccounts, activeAccountId] = await Promise.all([
      getItem(BASE_URL_KEY),
      getItem(ADMIN_KEY_KEY),
      getItem(ACCOUNTS_KEY),
      getItem(ACTIVE_ACCOUNT_ID_KEY),
    ]);

    let accounts: AdminAccountProfile[] = [];

    if (rawAccounts) {
      try {
        const parsed = JSON.parse(rawAccounts) as AdminAccountProfile[];
        accounts = Array.isArray(parsed) ? sanitizeAccountsForWeb(parsed.map((account) => normalizeAccount(account))) : [];
      } catch {
        accounts = [];
      }
    }

    if (accounts.length === 0 && baseUrl) {
      const legacyConfig = normalizeConfig({
        baseUrl,
        adminApiKey: IS_WEB ? defaults.adminApiKey : adminApiKey ?? defaults.adminApiKey,
      });

      accounts = [
        {
          id: createAccountId(),
          label: getAccountLabel(legacyConfig.baseUrl),
          ...legacyConfig,
          updatedAt: new Date().toISOString(),
          enabled: true,
        },
      ];
    }

    const sortedAccounts = sortAccounts(accounts);
    const activeAccount = getNextActiveAccount(sortedAccounts, activeAccountId ?? undefined);
    const nextActiveAccountId = activeAccount?.id || '';

    adminConfigState.accounts = sortedAccounts;
    adminConfigState.activeAccountId = nextActiveAccountId;
    adminConfigState.baseUrl = activeAccount?.baseUrl ?? defaults.baseUrl;
    adminConfigState.adminApiKey = activeAccount?.adminApiKey ?? defaults.adminApiKey;

    await Promise.all([
      persistAccounts(sortedAccounts),
      nextActiveAccountId ? setItem(ACTIVE_ACCOUNT_ID_KEY, nextActiveAccountId) : deleteItem(ACTIVE_ACCOUNT_ID_KEY),
      setItem(BASE_URL_KEY, activeAccount?.baseUrl ?? defaults.baseUrl),
      persistAdminApiKey(activeAccount?.adminApiKey ?? defaults.adminApiKey),
    ]);
  } finally {
    adminConfigState.hydrated = true;
  }
}

export async function saveAdminConfig(input: { baseUrl: string; adminApiKey: string }) {
  adminConfigState.saving = true;

  try {
    const normalized = normalizeConfig(input);
    const nextUpdatedAt = new Date().toISOString();
    const existingAccount = adminConfigState.accounts.find(
      (account: AdminAccountProfile) => account.baseUrl === normalized.baseUrl && account.adminApiKey === normalized.adminApiKey
    );
    const nextAccount: AdminAccountProfile = existingAccount
      ? {
          ...existingAccount,
          label: getAccountLabel(normalized.baseUrl),
          updatedAt: nextUpdatedAt,
        }
      : {
          id: createAccountId(),
          label: getAccountLabel(normalized.baseUrl),
          ...normalized,
          updatedAt: nextUpdatedAt,
          enabled: true,
        };
    const nextAccounts = sortAccounts([
      nextAccount,
      ...adminConfigState.accounts.filter((account: AdminAccountProfile) => account.id !== nextAccount.id),
    ]);

    await Promise.all([
      setItem(BASE_URL_KEY, normalized.baseUrl),
      persistAdminApiKey(normalized.adminApiKey),
      persistAccounts(nextAccounts),
      setItem(ACTIVE_ACCOUNT_ID_KEY, nextAccount.id),
    ]);

    adminConfigState.accounts = nextAccounts;
    adminConfigState.activeAccountId = nextAccount.id;
    adminConfigState.baseUrl = normalized.baseUrl;
    adminConfigState.adminApiKey = normalized.adminApiKey;
  } finally {
    adminConfigState.saving = false;
  }
}

export async function switchAdminAccount(accountId: string) {
  const account = adminConfigState.accounts.find((item: AdminAccountProfile) => item.id === accountId);

  if (!account) {
    return;
  }

  if (account.enabled === false) {
    return;
  }

  const nextAccount = {
    ...account,
    updatedAt: new Date().toISOString(),
  };
  const nextAccounts = sortAccounts([
    nextAccount,
    ...adminConfigState.accounts.filter((item: AdminAccountProfile) => item.id !== accountId),
  ]);

  await Promise.all([
    setItem(BASE_URL_KEY, nextAccount.baseUrl),
    persistAdminApiKey(nextAccount.adminApiKey),
    persistAccounts(nextAccounts),
    setItem(ACTIVE_ACCOUNT_ID_KEY, nextAccount.id),
  ]);

  adminConfigState.accounts = nextAccounts;
  adminConfigState.activeAccountId = nextAccount.id;
  adminConfigState.baseUrl = nextAccount.baseUrl;
  adminConfigState.adminApiKey = nextAccount.adminApiKey;
}

export async function removeAdminAccount(accountId: string) {
  const nextAccounts = adminConfigState.accounts.filter((item: AdminAccountProfile) => item.id !== accountId);
  const nextActiveAccount = getNextActiveAccount(nextAccounts, adminConfigState.activeAccountId === accountId ? '' : adminConfigState.activeAccountId);

  await Promise.all([
    persistAccounts(nextAccounts),
    nextActiveAccount ? setItem(ACTIVE_ACCOUNT_ID_KEY, nextActiveAccount.id) : deleteItem(ACTIVE_ACCOUNT_ID_KEY),
    setItem(BASE_URL_KEY, nextActiveAccount?.baseUrl ?? ''),
    persistAdminApiKey(nextActiveAccount?.adminApiKey ?? ''),
  ]);

  adminConfigState.accounts = nextAccounts;
  adminConfigState.activeAccountId = nextActiveAccount?.id ?? '';
  adminConfigState.baseUrl = nextActiveAccount?.baseUrl ?? '';
  adminConfigState.adminApiKey = nextActiveAccount?.adminApiKey ?? '';
}

export async function logoutAdminAccount() {
  await Promise.all([setItem(BASE_URL_KEY, ''), persistAdminApiKey(''), deleteItem(ACTIVE_ACCOUNT_ID_KEY)]);

  adminConfigState.activeAccountId = '';
  adminConfigState.baseUrl = '';
  adminConfigState.adminApiKey = '';
}

export async function setAdminAccountEnabled(accountId: string, enabled: boolean) {
  const nextAccounts = sortAccounts(
    adminConfigState.accounts.map((account: AdminAccountProfile) =>
      account.id === accountId ? { ...account, enabled, updatedAt: new Date().toISOString() } : account
    )
  );
  const nextActiveAccount = getNextActiveAccount(nextAccounts, enabled ? accountId : adminConfigState.activeAccountId);

  await Promise.all([
    persistAccounts(nextAccounts),
    nextActiveAccount ? setItem(ACTIVE_ACCOUNT_ID_KEY, nextActiveAccount.id) : deleteItem(ACTIVE_ACCOUNT_ID_KEY),
    setItem(BASE_URL_KEY, nextActiveAccount?.baseUrl ?? ''),
    persistAdminApiKey(nextActiveAccount?.adminApiKey ?? ''),
  ]);

  adminConfigState.accounts = nextAccounts;
  adminConfigState.activeAccountId = nextActiveAccount?.id ?? '';
  adminConfigState.baseUrl = nextActiveAccount?.baseUrl ?? '';
  adminConfigState.adminApiKey = nextActiveAccount?.adminApiKey ?? '';
}
