import {MembershipFromServer, ReadMembership} from '@modules/chats/interfaces';

import {Asset, AssetFromServer} from './asset';
import {Block} from './blockMessage';
import {ChatEventSubtype, ChatEventType} from './eventBase';
import {HighlightedSpan} from './highlightedSpan';
import {MediaEntity} from './media';
import {Reaction} from './reaction';

export enum MessageStatus {
  Sending = 'SENDING',
  Error = 'ERROR',
  Sent = 'SENT',
}

export type DeliverStatus = {
  read_at?: Nullable<string>;
  received_at?: Nullable<string>;
};

export interface Message {
  text: string;
  /**
   * Conversation id
   */
  channel: string;
  /**
   * Message ULID timestamp generated by the server. Used to apply mutations to the message with the server.
   * Use this to edit, delete, react to the message with the server and to paginate messages from the server.
   */
  ts: string;
  /**
   * Event ts when message is updated. Could change in new versions.
   * For now, we are not using this field. But it could be used in the future.
   */
  latest_event_ts?: string;
  /**
   * Message ULID timestamp of the message that this message is replying to.
   */
  reply_ts?: string;
  /**
   * User id
   */
  user: string;
  /**
   * Local attribute to store message status
   */
  status?: MessageStatus;
  /**
   * ULID client message id
   */
  client_msg_id: string;
  /**
   * Sender full name. This field could be:
   * - The same value as `UsersMapper.get(user_id)`
   * - The first_name + last_name of the user object retrieved from the server
   * This is because the message object could be saved before the user, when is a new message and a new user.
   */
  username: string;
  /**
   * Sender profile picture, this field could be:
   * - The same value as `UsersMapper.get(user_id)`
   * - The picture_asset_url of the user object retrieved from the server (need access token to get the image)
   * - The picture_url of the user object retrieved from the server (with S3 signature)
   * - `undefined` if the user does not have a profile picture
   * This is because the message object could be saved before the user, when is a new message and a new user.
   */
  sender_profile_picture?: string;
  /**
   * Message version.
   * This value starts in -1 if the message is created in the app.
   * Then, when the message is created in the server, the version is updated to 0.
   * Then, when the message is updated in the server, the version is incremented.
   */
  version: number;
  /**
   * Text height (this value is generated in the client)
   */
  height: number;

  blocks?: Block[];

  attachments?: Asset[];
  /**
   * Whether the message has been edited
   */
  edited?: boolean;
  /**
   * When the message is hidden, it means that the message has been deleted
   */
  hidden?: boolean;
  reactions?: Reaction[];
  /**
   * Highlighted spans in the message. Used to highlight mentions in the message.
   */
  highlighted_spans: HighlightedSpan[];
  /**
   * Formatted text with mentions
   */
  formatted_text: string;

  deliver_status?: DeliverStatus;
  deleted_from_ui?: boolean;
  /**
   * Whether the message has been forwarded
   */
  forwarded?: boolean;
  /**
   * Font scale that was used to calculate the height
   */
  associated_font_scale?: number;
  /**
   * Assets sending offline, pending to upload to server before sending current message
   */
  pendingAssets?: MediaEntity[];
  /**
   * Means the message was generated by an AI
   */
  generated_by?: GeneratedBy;
}

export type MessageEvent = {
  hu_data: {
    message_ts: string;
    version: number;
    picture_asset_url?: string;
    highlighted_spans: HighlightedSpan[];
    read_status?: DeliverStatus;
    /**
     * User id that sent the message
     **/
    sender_id: number;
    membership: ReadMembership;
    count_unread?: boolean; // Whether to count the message as unread, not the number of unread messages
    generated_by?: GeneratedBy;
  };
  type: ChatEventType;
  subtype?: ChatEventSubtype;
  channel: string;
  /**
   * User id that invokate the Event
   **/
  user: string;
  username: string;
  text: string;
  attachments: AssetFromServer[];
  ts: string;
  client_msg_id: string;
  edited?: {
    user: string;
    ts: string;
  };
  blocks?: Block[];
  hidden?: boolean;
  reactions?: Reaction[];
};

/**
 * Local conversation latest message interface
 */
export type ConversationLatest = Pick<
  Message,
  | 'text'
  | 'ts'
  | 'client_msg_id'
  | 'user'
  | 'username'
  | 'status'
  | 'blocks'
  | 'attachments'
  | 'version'
  | 'edited'
  | 'hidden'
  | 'highlighted_spans'
  | 'formatted_text'
  | 'deliver_status'
  | 'associated_font_scale'
  | 'deleted_from_ui'
  | 'pendingAssets'
  | 'generated_by'
>;

export type ConversationLatestFromServer = Pick<
  MessageEvent,
  | 'client_msg_id'
  | 'type'
  | 'username'
  | 'text'
  | 'attachments'
  | 'blocks'
  | 'ts'
  | 'edited'
  | 'subtype'
> & {
  highlighted_spans?: HighlightedSpan[];
  sender_id: number;
  read_status?: DeliverStatus;
  version?: number;
  generated_by?: GeneratedBy;
};

export type MessageInfoReadState = {
  read_at?: number;
  was_in_channel_when_message_sent?: boolean;
  user: MembershipFromServer & {
    last_read: string; //  ts
  };
};

export type SearchMessageMatchItem = {
  type: 'message';
  item: Pick<MessageEvent, 'text'> & {
    hu_data: Pick<MessageEvent['hu_data'], 'message_ts'>;
  };
};

export type SearchMessageMatchStoreItem = {
  ts: string;
  viewPosition: number; // 0..1
};

/**
 * The object exists in the message when the msg was generated by an AI
 * The name and origin fields are used to identify the AI that generated the message
 */
export type GeneratedBy = {
  name: 'note-summarizer'; // it can be any string
  origin: 'app'; // the server expects "app"
};
