/**
 * Domain Entity: Notification
 *
 * Represents a notification sent to a user.
 * Immutable entity with factory methods and domain validation.
 */

import type { IEntity } from '@core/shared/domain';
import { NotificationDomainError } from '../errors/NotificationDomainError';
import { NotificationId } from '../value-objects/NotificationId';

import type { NotificationType, NotificationChannel } from '../types/NotificationTypes';

export type NotificationStatus = 'unread' | 'read' | 'dismissed' | 'action_required';

/**
 * Notification urgency determines how the notification is displayed
 * - silent: Only appears in notification center (default)
 * - toast: Shows a temporary toast notification
 * - modal: Shows a blocking modal that requires user action (cannot be ignored)
 */
export type NotificationUrgency = 'silent' | 'toast' | 'modal';

export interface NotificationData {
  /** Reference to related protest */
  protestId?: string;
  /** Reference to related race */
  raceId?: string;
  /** Reference to related league */
  leagueId?: string;
  /** Reference to related driver (e.g., who filed protest) */
  actorDriverId?: string;
  /** Reference to related penalty */
  penaltyId?: string;
  /** Reference to related team */
  teamId?: string;
  /** Deadline for action (e.g., defense deadline) */
  deadline?: Date;
  /** Any additional context data */
  [key: string]: unknown;
}

/**
 * Configuration for action buttons shown on modal notifications
 */
export interface NotificationAction {
  /** Button label */
  label: string;
  /** Action type - determines styling */
  type: 'primary' | 'secondary' | 'danger';
  /** URL to navigate to when clicked */
  href?: string;
  /** Custom action identifier (for handling in code) */
  actionId?: string;
}

export interface NotificationProps {
  id: NotificationId;
  /** Driver who receives this notification */
  recipientId: string;
  /** Type of notification */
  type: NotificationType;
  /** Human-readable title */
  title: string;
  /** Notification body/message */
  body: string;
  /** Channel this notification was/will be sent through */
  channel: NotificationChannel;
  /** Current status */
  status: NotificationStatus;
  /** How urgently to display this notification */
  urgency: NotificationUrgency;
  /** Structured data for linking/context */
  data?: NotificationData;
  /** Optional action URL (for simple click-through) */
  actionUrl?: string;
  /** Action buttons for modal notifications */
  actions?: NotificationAction[];
  /** Whether this notification requires a response before it can be dismissed */
  requiresResponse?: boolean;
  /** When the notification was created */
  createdAt: Date;
  /** When the notification was read (if applicable) */
  readAt?: Date;
  /** When the notification was responded to (for action_required status) */
  respondedAt?: Date;
}

export class Notification implements IEntity<string> {
  private constructor(private readonly props: NotificationProps) {}

  static create(props: Omit<NotificationProps, 'id' | 'status' | 'createdAt' | 'urgency'> & {
    id: string;
    status?: NotificationStatus;
    createdAt?: Date;
    urgency?: NotificationUrgency;
  }): Notification {
    const id = NotificationId.create(props.id);

    if (!props.recipientId) throw new NotificationDomainError('Recipient ID is required');
    if (!props.type) throw new NotificationDomainError('Notification type is required');
    if (!props.title?.trim()) throw new NotificationDomainError('Notification title is required');
    if (!props.body?.trim()) throw new NotificationDomainError('Notification body is required');
    if (!props.channel) throw new NotificationDomainError('Notification channel is required');

    // Modal notifications that require response start with action_required status
    const defaultStatus = props.requiresResponse ? 'action_required' : 'unread';

    return new Notification({
      ...props,
      id,
      status: props.status ?? defaultStatus,
      urgency: props.urgency ?? 'silent',
      createdAt: props.createdAt ?? new Date(),
    });
  }

  get id(): string { return this.props.id.value; }
  get recipientId(): string { return this.props.recipientId; }
  get type(): NotificationType { return this.props.type; }
  get title(): string { return this.props.title; }
  get body(): string { return this.props.body; }
  get channel(): NotificationChannel { return this.props.channel; }
  get status(): NotificationStatus { return this.props.status; }
  get urgency(): NotificationUrgency { return this.props.urgency; }
  get data(): NotificationData | undefined { return this.props.data ? { ...this.props.data } : undefined; }
  get actionUrl(): string | undefined { return this.props.actionUrl; }
  get actions(): NotificationAction[] | undefined { return this.props.actions ? [...this.props.actions] : undefined; }
  get requiresResponse(): boolean { return this.props.requiresResponse ?? false; }
  get createdAt(): Date { return this.props.createdAt; }
  get readAt(): Date | undefined { return this.props.readAt; }
  get respondedAt(): Date | undefined { return this.props.respondedAt; }

  isUnread(): boolean {
    return this.props.status === 'unread';
  }

  isRead(): boolean {
    return this.props.status === 'read';
  }

  isDismissed(): boolean {
    return this.props.status === 'dismissed';
  }

  isActionRequired(): boolean {
    return this.props.status === 'action_required';
  }

  isSilent(): boolean {
    return this.props.urgency === 'silent';
  }

  isToast(): boolean {
    return this.props.urgency === 'toast';
  }

  isModal(): boolean {
    return this.props.urgency === 'modal';
  }

  /**
   * Check if this notification can be dismissed without responding
   */
  canDismiss(): boolean {
    return !this.props.requiresResponse || this.props.status !== 'action_required';
  }

  /**
   * Mark the notification as read
   */
  markAsRead(): Notification {
    if (this.props.status !== 'unread') {
      return this; // Already read or dismissed, no change
    }
    return new Notification({
      ...this.props,
      status: 'read',
      readAt: new Date(),
    });
  }

  /**
   * Mark that the user has responded to an action_required notification
   */
  markAsResponded(actionId?: string): Notification {
    const data =
      actionId !== undefined
        ? { ...(this.props.data ?? {}), responseActionId: actionId }
        : this.props.data;

    return new Notification({
      ...this.props,
      status: 'read',
      readAt: this.props.readAt ?? new Date(),
      respondedAt: new Date(),
      ...(data !== undefined ? { data } : {}),
    });
  }

  /**
   * Dismiss the notification
   */
  dismiss(): Notification {
    if (this.props.status === 'dismissed') {
      return this; // Already dismissed
    }
    // Cannot dismiss action_required notifications without responding
    if (this.props.requiresResponse && this.props.status === 'action_required') {
      throw new NotificationDomainError('Cannot dismiss notification that requires response');
    }
    return new Notification({
      ...this.props,
      status: 'dismissed',
      readAt: this.props.readAt ?? new Date(),
    });
  }

  /**
   * Convert to plain object for serialization
   */
  toJSON(): Omit<NotificationProps, 'id'> & { id: string } {
    return {
      ...this.props,
      id: this.props.id.value,
    };
  }
}