import Constants from 'expo-constants';
import * as Notifications from 'expo-notifications';
import * as SecureStore from 'expo-secure-store';
import { Platform } from 'react-native';

import { registerMobilePushDevice } from '@/src/lib/api';

const DEVICE_ID_KEY = 'fedeo.mobilePush.localDeviceId';

Notifications.setNotificationHandler({
  handleNotification: async () => ({
    shouldPlaySound: true,
    shouldSetBadge: true,
    shouldShowBanner: true,
    shouldShowList: true,
  }),
});

function createLocalDeviceId(): string {
  const random = typeof crypto !== 'undefined' && 'randomUUID' in crypto
    ? crypto.randomUUID()
    : `${Date.now()}-${Math.random().toString(36).slice(2)}`;

  return `mobile-${random}`;
}

async function getLocalDeviceId() {
  const existing = await SecureStore.getItemAsync(DEVICE_ID_KEY);
  if (existing) return existing;

  const created = createLocalDeviceId();
  await SecureStore.setItemAsync(DEVICE_ID_KEY, created);
  return created;
}

async function ensurePushPermission() {
  const current = await Notifications.getPermissionsAsync();
  if (hasPushPermission(current)) return;

  const requested = await Notifications.requestPermissionsAsync();
  if (!hasPushPermission(requested)) {
    throw new Error('Push-Mitteilungen wurden nicht erlaubt.');
  }
}

function hasPushPermission(status: unknown): boolean {
  const permission = status as { granted?: boolean; status?: string };
  return permission.granted === true || permission.status === 'granted';
}

export async function registerDeviceForPush(token: string) {
  if (Platform.OS !== 'ios' && Platform.OS !== 'android') {
    throw new Error('Mobile Push ist nur auf iOS und Android verfügbar.');
  }

  await ensurePushPermission();

  const deviceToken = await Notifications.getDevicePushTokenAsync();
  const providerToken = String(deviceToken.data || '');
  if (!providerToken) {
    throw new Error('Es wurde kein nativer Push-Token zurückgegeben.');
  }

  return await registerMobilePushDevice(token, {
    localDeviceId: await getLocalDeviceId(),
    platform: Platform.OS,
    providerToken,
    deviceLabel: Constants.deviceName || `${Platform.OS} Gerät`,
    meta: {
      os: Platform.OS,
      osVersion: Platform.Version,
      expoRuntimeVersion: Constants.expoConfig?.runtimeVersion || null,
      appVersion: Constants.expoConfig?.version || null,
    },
  });
}
