import { secureSessionStorage, clearMobileSessionStorage, MOBILE_SESSION_STORAGE_KEY } from '@/lib/secureSessionStorage';
import { createMobilePlatformSdk, mobileRuntime } from '@/lib/runtime';

export interface PlatformAuthUser {
  id: string;
  email?: string;
  role?: string;
  plan?: string;
  displayName?: string;
}

export interface StoredPlatformSession {
  accessToken: string;
  refreshToken: string;
  user: PlatformAuthUser;
}

class PlatformAuthError extends Error {
  status?: number;

  constructor(message: string, status?: number) {
    super(message);
    this.name = 'PlatformAuthError';
    this.status = status;
  }
}

function createPlatformAuthSdk(accessToken: string | null = null) {
  return createMobilePlatformSdk(() => accessToken);
}

function normalizeUser(value: any): PlatformAuthUser {
  return {
    id: String(value?.id || value?.sub || '').trim(),
    email: typeof value?.email === 'string' ? value.email : undefined,
    role: typeof value?.role === 'string' ? value.role : undefined,
    plan: typeof value?.plan === 'string' ? value.plan : undefined,
    displayName: typeof value?.displayName === 'string' ? value.displayName : undefined,
  };
}

async function platformRequest<T>(
  path: string,
  options?: {
    method?: string;
    accessToken?: string;
    body?: Record<string, unknown>;
  }
): Promise<T> {
  const sdk = createPlatformAuthSdk(options?.accessToken ?? null);
  const response = await sdk.fetch(path, {
    method: options?.method || 'GET',
    body: options?.body ? JSON.stringify(options.body) : undefined,
  });

  const payload = await response.json().catch(() => ({}));
  if (!response.ok) {
    throw new PlatformAuthError(
      String((payload as { message?: string; error?: string }).message || (payload as { error?: string }).error || `HTTP ${response.status}`),
      response.status
    );
  }

  return payload as T;
}

function isStoredSession(value: unknown): value is StoredPlatformSession {
  const candidate = value as StoredPlatformSession | null;
  return Boolean(
    candidate
      && typeof candidate.accessToken === 'string'
      && typeof candidate.refreshToken === 'string'
      && candidate.user
      && typeof candidate.user.id === 'string'
  );
}

async function writeSession(session: StoredPlatformSession): Promise<void> {
  await secureSessionStorage.setItem(MOBILE_SESSION_STORAGE_KEY, JSON.stringify(session));
}

export async function persistPlatformSession(session: StoredPlatformSession): Promise<void> {
  await writeSession(session);
}

export async function readPlatformSession(): Promise<StoredPlatformSession | null> {
  const raw = await secureSessionStorage.getItem(MOBILE_SESSION_STORAGE_KEY);
  if (!raw) {
    return null;
  }

  try {
    const parsed = JSON.parse(raw) as unknown;
    return isStoredSession(parsed) ? parsed : null;
  } catch {
    return null;
  }
}

export async function clearPlatformSession(): Promise<void> {
  await clearMobileSessionStorage();
}

export async function getCurrentPlatformUser(accessToken: string): Promise<PlatformAuthUser> {
  const me = await platformRequest<any>('/auth/me', {
    accessToken,
  });
  return normalizeUser(me);
}

export async function refreshPlatformSession(refreshToken: string): Promise<StoredPlatformSession> {
  const refreshed = await platformRequest<{ accessToken: string; refreshToken: string }>('/auth/refresh', {
    method: 'POST',
    body: { refreshToken },
  });
  const user = await getCurrentPlatformUser(refreshed.accessToken);
  const session: StoredPlatformSession = {
    accessToken: refreshed.accessToken,
    refreshToken: refreshed.refreshToken,
    user,
  };
  await writeSession(session);
  return session;
}

export async function syncPlatformSessionFromTokens(
  accessToken: string,
  refreshToken: string
): Promise<StoredPlatformSession> {
  const user = await getCurrentPlatformUser(accessToken);
  const session: StoredPlatformSession = {
    accessToken,
    refreshToken,
    user,
  };
  await writeSession(session);
  return session;
}

export async function restorePlatformSession(): Promise<StoredPlatformSession | null> {
  const stored = await readPlatformSession();
  if (!stored) {
    return null;
  }

  try {
    const user = await getCurrentPlatformUser(stored.accessToken);
    const session = { ...stored, user };
    await writeSession(session);
    return session;
  } catch (error) {
    if ((error as PlatformAuthError)?.status === 401 || (error as PlatformAuthError)?.status === 403) {
      try {
        return await refreshPlatformSession(stored.refreshToken);
      } catch {
        await clearPlatformSession();
        return null;
      }
    }
    throw error;
  }
}

export async function loginPlatformSession(email: string, password: string): Promise<StoredPlatformSession> {
  const response = await platformRequest<{
    accessToken: string;
    refreshToken: string;
    user: PlatformAuthUser;
  }>('/auth/login', {
    method: 'POST',
    body: {
      email,
      password,
      productId: mobileRuntime.productId,
    },
  });

  const session: StoredPlatformSession = {
    accessToken: response.accessToken,
    refreshToken: response.refreshToken,
    user: normalizeUser(response.user),
  };
  await writeSession(session);
  return session;
}
