import { Result, ok, err } from '../../../../../shared/core/Result';
import { UseCase } from '../../../../../shared/core/UseCase';
import { UseCaseError } from '../../../../../shared/core/UseCaseError';
import { AppError } from '../../../../../shared/core/AppError';
import { CuratorId } from '../../../../cards/domain/value-objects/CuratorId';
import { CardId } from '../../../../cards/domain/value-objects/CardId';
import { CollectionId } from '../../../../cards/domain/value-objects/CollectionId';
import { ConnectionId } from '../../../../cards/domain/value-objects/ConnectionId';
import { NotificationService } from '../../../domain/services/NotificationService';
import { NotificationType } from '@semble/types';

export interface CreateUserAddedYourCardNotificationDTO {
  type: NotificationType.USER_ADDED_YOUR_CARD;
  recipientUserId: string;
  actorUserId: string;
  cardId: string;
  collectionIds?: string[];
}

export interface CreateUserAddedToYourCollectionNotificationDTO {
  type: NotificationType.USER_ADDED_TO_YOUR_COLLECTION;
  recipientUserId: string;
  actorUserId: string;
  cardId: string;
  collectionId: string;
}

export interface CreateUserAddedYourBskyPostNotificationDTO {
  type: NotificationType.USER_ADDED_YOUR_BSKY_POST;
  recipientUserId: string;
  actorUserId: string;
  cardId: string;
  collectionIds?: string[];
}

export interface CreateUserAddedYourCollectionNotificationDTO {
  type: NotificationType.USER_ADDED_YOUR_COLLECTION;
  recipientUserId: string;
  actorUserId: string;
  cardId: string;
  collectionIds?: string[];
}

export interface CreateUserConnectedYourUrlNotificationDTO {
  type: NotificationType.USER_CONNECTED_YOUR_URL;
  recipientUserId: string;
  actorUserId: string;
  connectionId: string;
}

export interface CreateUserConnectedYourPostNotificationDTO {
  type: NotificationType.USER_CONNECTED_YOUR_POST;
  recipientUserId: string;
  actorUserId: string;
  connectionId: string;
}

export interface CreateUserConnectedYourCollectionNotificationDTO {
  type: NotificationType.USER_CONNECTED_YOUR_COLLECTION;
  recipientUserId: string;
  actorUserId: string;
  connectionId: string;
}

export type CreateNotificationDTO =
  | CreateUserAddedYourCardNotificationDTO
  | CreateUserAddedToYourCollectionNotificationDTO
  | CreateUserAddedYourBskyPostNotificationDTO
  | CreateUserAddedYourCollectionNotificationDTO
  | CreateUserConnectedYourUrlNotificationDTO
  | CreateUserConnectedYourPostNotificationDTO
  | CreateUserConnectedYourCollectionNotificationDTO;

export interface CreateNotificationResponseDTO {
  notificationId: string;
}

export class ValidationError extends UseCaseError {
  constructor(message: string) {
    super(message);
  }
}

export class CreateNotificationUseCase
  implements
    UseCase<
      CreateNotificationDTO,
      Result<
        CreateNotificationResponseDTO,
        ValidationError | AppError.UnexpectedError
      >
    >
{
  constructor(private notificationService: NotificationService) {}

  async execute(
    request: CreateNotificationDTO,
  ): Promise<
    Result<
      CreateNotificationResponseDTO,
      ValidationError | AppError.UnexpectedError
    >
  > {
    try {
      // Validate and create recipient CuratorId
      const recipientIdResult = CuratorId.create(request.recipientUserId);
      if (recipientIdResult.isErr()) {
        return err(
          new ValidationError(
            `Invalid recipient ID: ${recipientIdResult.error.message}`,
          ),
        );
      }
      const recipientId = recipientIdResult.value;

      // Validate and create actor CuratorId
      const actorIdResult = CuratorId.create(request.actorUserId);
      if (actorIdResult.isErr()) {
        return err(
          new ValidationError(
            `Invalid actor ID: ${actorIdResult.error.message}`,
          ),
        );
      }
      const actorId = actorIdResult.value;

      // Handle different notification types
      let notificationResult;

      if (request.type === NotificationType.USER_ADDED_YOUR_CARD) {
        // Validate and create CardId
        const cardIdResult = CardId.createFromString(request.cardId);
        if (cardIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid card ID: ${cardIdResult.error.message}`,
            ),
          );
        }
        const cardId = cardIdResult.value;

        // Validate collection IDs if provided
        let collectionIds: CollectionId[] | undefined;
        if (request.collectionIds && request.collectionIds.length > 0) {
          collectionIds = [];
          for (const collectionIdStr of request.collectionIds) {
            const collectionIdResult =
              CollectionId.createFromString(collectionIdStr);
            if (collectionIdResult.isErr()) {
              return err(
                new ValidationError(
                  `Invalid collection ID: ${collectionIdResult.error.message}`,
                ),
              );
            }
            collectionIds.push(collectionIdResult.value);
          }
        }

        notificationResult =
          await this.notificationService.createUserAddedYourCardNotification(
            recipientId,
            actorId,
            cardId,
            collectionIds,
          );
      } else if (
        request.type === NotificationType.USER_ADDED_TO_YOUR_COLLECTION
      ) {
        // Validate and create CardId
        const cardIdResult = CardId.createFromString(request.cardId);
        if (cardIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid card ID: ${cardIdResult.error.message}`,
            ),
          );
        }
        const cardId = cardIdResult.value;

        // Validate collection ID
        const collectionIdResult = CollectionId.createFromString(
          request.collectionId,
        );
        if (collectionIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid collection ID: ${collectionIdResult.error.message}`,
            ),
          );
        }

        notificationResult =
          await this.notificationService.createUserAddedToYourCollectionNotification(
            recipientId,
            actorId,
            cardId,
            collectionIdResult.value,
          );
      } else if (request.type === NotificationType.USER_ADDED_YOUR_BSKY_POST) {
        // Validate and create CardId
        const cardIdResult = CardId.createFromString(request.cardId);
        if (cardIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid card ID: ${cardIdResult.error.message}`,
            ),
          );
        }
        const cardId = cardIdResult.value;

        // Validate collection IDs if provided
        let collectionIds: CollectionId[] | undefined;
        if (request.collectionIds && request.collectionIds.length > 0) {
          collectionIds = [];
          for (const collectionIdStr of request.collectionIds) {
            const collectionIdResult =
              CollectionId.createFromString(collectionIdStr);
            if (collectionIdResult.isErr()) {
              return err(
                new ValidationError(
                  `Invalid collection ID: ${collectionIdResult.error.message}`,
                ),
              );
            }
            collectionIds.push(collectionIdResult.value);
          }
        }

        notificationResult =
          await this.notificationService.createUserAddedYourBskyPostNotification(
            recipientId,
            actorId,
            cardId,
            collectionIds,
          );
      } else if (request.type === NotificationType.USER_ADDED_YOUR_COLLECTION) {
        // Validate and create CardId
        const cardIdResult = CardId.createFromString(request.cardId);
        if (cardIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid card ID: ${cardIdResult.error.message}`,
            ),
          );
        }
        const cardId = cardIdResult.value;

        // Validate collection IDs if provided
        let collectionIds: CollectionId[] | undefined;
        if (request.collectionIds && request.collectionIds.length > 0) {
          collectionIds = [];
          for (const collectionIdStr of request.collectionIds) {
            const collectionIdResult =
              CollectionId.createFromString(collectionIdStr);
            if (collectionIdResult.isErr()) {
              return err(
                new ValidationError(
                  `Invalid collection ID: ${collectionIdResult.error.message}`,
                ),
              );
            }
            collectionIds.push(collectionIdResult.value);
          }
        }

        notificationResult =
          await this.notificationService.createUserAddedYourCollectionNotification(
            recipientId,
            actorId,
            cardId,
            collectionIds,
          );
      } else if (request.type === NotificationType.USER_CONNECTED_YOUR_URL) {
        // Validate connection ID
        const connectionIdResult = ConnectionId.createFromString(
          request.connectionId,
        );
        if (connectionIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid connection ID: ${connectionIdResult.error.message}`,
            ),
          );
        }

        notificationResult =
          await this.notificationService.createUserConnectedYourUrlNotification(
            recipientId,
            actorId,
            connectionIdResult.value,
          );
      } else if (request.type === NotificationType.USER_CONNECTED_YOUR_POST) {
        // Validate connection ID
        const connectionIdResult = ConnectionId.createFromString(
          request.connectionId,
        );
        if (connectionIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid connection ID: ${connectionIdResult.error.message}`,
            ),
          );
        }

        notificationResult =
          await this.notificationService.createUserConnectedYourPostNotification(
            recipientId,
            actorId,
            connectionIdResult.value,
          );
      } else if (
        request.type === NotificationType.USER_CONNECTED_YOUR_COLLECTION
      ) {
        // Validate connection ID
        const connectionIdResult = ConnectionId.createFromString(
          request.connectionId,
        );
        if (connectionIdResult.isErr()) {
          return err(
            new ValidationError(
              `Invalid connection ID: ${connectionIdResult.error.message}`,
            ),
          );
        }

        notificationResult =
          await this.notificationService.createUserConnectedYourCollectionNotification(
            recipientId,
            actorId,
            connectionIdResult.value,
          );
      } else {
        // Type exhaustiveness check
        const _exhaustiveCheck: never = request;
        return err(
          new ValidationError(
            `Unsupported notification type: ${(_exhaustiveCheck as any).type}`,
          ),
        );
      }

      if (notificationResult.isErr()) {
        return err(new ValidationError(notificationResult.error.message));
      }

      return ok({
        notificationId:
          notificationResult.value.notificationId.getStringValue(),
      });
    } catch (error) {
      return err(AppError.UnexpectedError.create(error));
    }
  }
}
