import pick from 'lodash/pick';
import type { LiteralUnion } from 'type-fest';

import type { EventType } from '../store/models';
import { Event } from '../store/models/event';
import { events } from './event';
import { context } from './context';

const API_VERSION = '2023-09-05';

export async function createEvent(scope: string, type: LiteralUnion<EventType, string>, model: any, options: any = {}) {
  const data: any = {
    object: model.dataValues,
  };
  if (type.endsWith('updated')) {
    data.previous_attributes = pick(model._previousDataValues, options.fields);
  }
  // console.log('createEvent', scope, type, data, options);
  const event = await Event.create({
    type,
    api_version: API_VERSION,
    livemode: !!model.livemode,
    object_id: model.id,
    object_type: scope,
    data,
    request: {
      // FIXME:
      id: '',
      idempotency_key: '',
      requested_by: options.requestedBy || context.getRequestedBy() || 'system',
    },
    metadata: {},
    pending_webhooks: 99, // force all events goto the event queue
  });

  events.emit('event.created', { id: event.id });
  events.emit(event.type, data.object, options);
}

export async function createStatusEvent(
  scope: string,
  prefix: string,
  config: Record<string, string>,
  model: any,
  options: any = {}
) {
  if (options.fields.includes('status') === false) {
    return;
  }

  const data: any = {
    object: model.dataValues,
    previous_attributes: pick(model._previousDataValues, options.fields),
  };

  if (!config[data.object.status]) {
    return;
  }

  // console.log('createStatusEvent', scope, prefix, config, data, options);
  const suffix = config[data.object.status];
  const event = await Event.create({
    type: [prefix, suffix].join('.'),
    api_version: API_VERSION,
    livemode: !!model.livemode,
    object_id: model.id,
    object_type: scope,
    data,
    request: {
      // FIXME:
      id: '',
      idempotency_key: '',
      requested_by: options.requestedBy || context.getRequestedBy() || 'system',
    },
    metadata: {},
    pending_webhooks: 99, // force all events goto the event queue
  });

  events.emit('event.created', { id: event.id });
  events.emit(event.type, data.object);
}

export async function createCustomEvent(
  scope: string,
  prefix: string,
  type: (current: any, previous: any) => string,
  model: any,
  options: any
) {
  const data: any = {
    object: model.dataValues,
    previous_attributes: pick(model._previousDataValues, options.fields),
  };

  const suffix = type(data.object, data.previous_attributes);
  if (!suffix) {
    return;
  }

  // console.log('createCustomEvent', scope, prefix, type, data, options);
  const event = await Event.create({
    type: [prefix, suffix].join('.'),
    api_version: API_VERSION,
    livemode: !!model.livemode,
    object_id: model.id,
    object_type: scope,
    data,
    request: {
      // FIXME:
      id: '',
      idempotency_key: '',
      requested_by: options.requestedBy || context.getRequestedBy() || 'system',
    },
    metadata: {},
    pending_webhooks: 99, // force all events goto the event queue
  });

  events.emit('event.created', { id: event.id });
  events.emit(event.type, data.object);
}

/**
 * 创建自定义事件，无需依赖模型对象
 * @param type 完整的事件类型，格式为 prefix.suffix
 * @param objectType 对象类型
 * @param objectId 对象ID
 * @param data 事件数据
 * @param options 额外选项
 */
export async function createFlexibleEvent(
  type: string,
  objectType: string,
  objectId: string,
  data: Record<string, any>,
  options: {
    livemode?: boolean;
    requestedBy?: string;
    metadata?: Record<string, any>;
  } = {}
) {
  const { livemode = false, requestedBy, metadata = {} } = options;

  const event = await Event.create({
    type,
    api_version: API_VERSION,
    livemode,
    object_id: objectId,
    object_type: objectType,
    data,
    request: {
      id: '',
      idempotency_key: '',
      requested_by: requestedBy || context.getRequestedBy() || 'system',
    },
    metadata,
    pending_webhooks: 99, // force all events goto the event queue
  });

  events.emit('event.created', { id: event.id });
  events.emit(type, data);
  return event;
}
