import { atom } from 'jotai';
import { atomFamily } from 'jotai/utils';
import { Descendant } from 'slate';
import { EncryptedAttachmentInfo } from 'browser-encrypt-attachment';
import { IEventRelation } from 'matrix-js-sdk';
import { createUploadAtomFamily } from '../upload';
import { TUploadContent } from '../../utils/matrix';
import { createListAtom } from '../list';

export type TUploadMetadata = {
  markedAsSpoiler: boolean;
};

export type TUploadItem = {
  file: TUploadContent;
  originalFile: TUploadContent;
  metadata: TUploadMetadata;
  encInfo: EncryptedAttachmentInfo | undefined;
};

export type TUploadListAtom = ReturnType<typeof createListAtom<TUploadItem>>;

// M2/M3b draft key: (roomId, threadKey). `threadKey === 'main'` for the
// channel/DM/legacy composer (preserves pre-M2 semantics), or `rootId`
// for the per-thread composer in `ThreadDrawer`. Tuple key requires a
// custom equality function — without it, atomFamily uses
// reference-equality on the array and every render gets a fresh atom.
//
// The plan slated this extension as M3b, but pulling the change forward
// into M2 is necessary: drawer composer and channel composer share the
// same `roomId`, so a single-key family clobbers each other's drafts on
// open/close (typing in the thread drawer leaks back into the channel
// composer when the drawer unmounts).
export type DraftKey = readonly [roomId: string, threadKey: string];
export const draftKey = (roomId: string, threadId?: string): DraftKey =>
  [roomId, threadId ?? 'main'] as const;
const draftKeyEqual = (a: DraftKey, b: DraftKey) => a[0] === b[0] && a[1] === b[1];

export const roomIdToUploadItemsAtomFamily = atomFamily<DraftKey, TUploadListAtom>(
  createListAtom,
  draftKeyEqual
);

export const roomUploadAtomFamily = createUploadAtomFamily();

export type RoomIdToMsgAction =
  | {
      type: 'PUT';
      roomId: string;
      msg: Descendant[];
    }
  | {
      type: 'DELETE';
      roomId: string;
    };

const createMsgDraftAtom = () => atom<Descendant[]>([]);
export type TMsgDraftAtom = ReturnType<typeof createMsgDraftAtom>;
export const roomIdToMsgDraftAtomFamily = atomFamily<DraftKey, TMsgDraftAtom>(
  () => createMsgDraftAtom(),
  draftKeyEqual
);

export type IReplyDraft = {
  userId: string;
  eventId: string;
  body: string;
  formattedBody?: string | undefined;
  relation?: IEventRelation | undefined;
};
const createReplyDraftAtom = () => atom<IReplyDraft | undefined>(undefined);
export type TReplyDraftAtom = ReturnType<typeof createReplyDraftAtom>;
export const roomIdToReplyDraftAtomFamily = atomFamily<DraftKey, TReplyDraftAtom>(
  () => createReplyDraftAtom(),
  draftKeyEqual
);
