package com.airlock.iam.admin.infrastructure.service.token.airlock2fa;

import com.airlock.iam.admin.domain.model.token.airlock2fa.Airlock2FAAdminAppDevice;
import com.airlock.iam.airlock2fa.api.domain.model.Airlock2FADeviceId;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAppDeviceType;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAAppDeviceVersion;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FADeviceDisplayName;
import com.airlock.iam.factor.domain.model.airlock2fa.Airlock2FAHardwareTokenActivationCode;
import com.airlock.iam.factor.domain.model.airlock2fa.hardware.Airlock2FAAdminHardwareDevice;
import com.airlock.iam.factor.domain.model.airlock2fa.hardware.Airlock2FAHardwareTokenId;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeHardwareDevice;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.FuturaeResponseMapper;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.transfer.FuturaeHardwareToken;
import com.airlock.iam.factor.infrastructure.rest.airlock2fa.futurae.transfer.FuturaeUserDevice;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public final class FuturaeAdminApiDeviceResponseMapper {
   public static List<Airlock2FAAdminAppDevice> toAppDevices(Collection<FuturaeUserDevice> devices) {
      return devices.stream()
         .peek(
            d -> Preconditions.checkArgument(
               appDeviceType(d).isPresent(), "Expected user device type to be one of the app devices types, but was: %s", d.getType()
            )
         )
         .map(d -> toAppDevice(d))
         .collect(Collectors.toList());
   }

   private static Airlock2FAAdminAppDevice toAppDevice(FuturaeUserDevice device) {
      Airlock2FAAdminAppDevice.Airlock2FAAdminAppDeviceBuilder deviceBuilder = Airlock2FAAdminAppDevice.builder()
         .deviceId(Airlock2FADeviceId.airlock2FADeviceId(device.getDeviceId()))
         .displayName(device.getDisplayName())
         .type(appDeviceType(device).orElseThrow())
         .assignedAt(Date.from(device.getEnrolledAt()))
         .createdAt(Date.from(device.getCreatedAt()))
         .capabilities(FuturaeResponseMapper.mapCapabilities(device.getCapabilities()));
      Optional.ofNullable(device.getVersion()).ifPresent(version -> deviceBuilder.appVersion(Airlock2FAAppDeviceVersion.appDeviceVersion(version)));
      Optional.ofNullable(device.getVersionSupported()).ifPresent(deviceBuilder::appVersionSupported);
      return deviceBuilder.build();
   }

   static Optional<Airlock2FAAppDeviceType> appDeviceType(FuturaeUserDevice device) {
      return switch (Strings.nullToEmpty(device.getType())) {
         case "android" -> Optional.of(Airlock2FAAppDeviceType.ANDROID);
         case "ios" -> Optional.of(Airlock2FAAppDeviceType.IOS);
         default -> Optional.empty();
      };
   }

   public static List<Airlock2FAAdminHardwareDevice> toHardwareDevices(Collection<FuturaeHardwareDevice> futuraeHardwareDevices) {
      return futuraeHardwareDevices.stream().map(d -> toHardwareDevice(d)).collect(Collectors.toList());
   }

   private static Airlock2FAAdminHardwareDevice toHardwareDevice(FuturaeHardwareDevice futuraeHardwareDevice) {
      return toHardwareDevice(futuraeHardwareDevice.userDevice(), futuraeHardwareDevice.hardwareToken());
   }

   private static Airlock2FAAdminHardwareDevice toHardwareDevice(FuturaeUserDevice device, FuturaeHardwareToken hardwareToken) {
      return Airlock2FAAdminHardwareDevice.builder()
         .deviceId(Airlock2FADeviceId.airlock2FADeviceId(device.getDeviceId()))
         .hardwareTokenId(Airlock2FAHardwareTokenId.airlock2FAHardwareTokenId(hardwareToken.getHardwareTokenId()))
         .displayName(Airlock2FADeviceDisplayName.airlock2FADeviceDisplayName(device.getDisplayName()))
         .manufacturer(hardwareToken.getManufacturer())
         .model(hardwareToken.getModel())
         .serialNumber(hardwareToken.getSerialNumber())
         .assignedAt(Date.from(device.getEnrolledAt()))
         .createdAt(Date.from(device.getCreatedAt()))
         .capabilities(FuturaeResponseMapper.mapCapabilities(device.getCapabilities()))
         .activationCode(
            Optional.ofNullable(hardwareToken.getActivationCode()).map(Airlock2FAHardwareTokenActivationCode::airlock2FAHardwareTokenActivationCode)
         )
         .build();
   }

   private FuturaeAdminApiDeviceResponseMapper() {
      throw new AssertionError();
   }
}
