import {
  AttachmentBuilder,
  type Guild,
  type GuildMember,
  type MessageCreateOptions,
  type SendableChannels,
  type TextBasedChannel
} from 'discord.js';
import { createCanvas, loadImage } from '@napi-rs/canvas';
import { buildEmbedFromPayload } from '../../lib/embed-payload.js';
import { buildComponentsV2Payload } from '../../lib/components-v2-payload.js';
import type { LeavePayload, WelcomePayload } from './service.js';
import { renderWelcomeEmbedText, renderWelcomeText } from './service.js';

export async function buildWelcomeMessage(
  payload: WelcomePayload,
  member: GuildMember,
  guild: Guild
): Promise<MessageCreateOptions> {
  if (payload.type === 'COMPONENTS_V2') {
    const componentsPayload = buildComponentsV2Payload(payload.components, {
      source: 'w',
      ref: guild.id,
      renderText: (value) => renderWelcomeText(value, member, guild)
    });
    if (componentsPayload) {
      return componentsPayload;
    }
    return { content: renderWelcomeText('{user}', member, guild) };
  }

  if (payload.type === 'EMBED') {
    const embed = buildEmbedFromPayload(payload.embed, {
      renderText: (value, field) => renderWelcomeEmbedText(value, member, guild, field),
      defaultThumbnailUrl: member.user.displayAvatarURL({ size: 256 })
    });
    return embed ? { embeds: [embed] } : { content: renderWelcomeText('{user}', member, guild) };
  }

  if (payload.type === 'IMAGE') {
    const buffer = await renderWelcomeCard(member, guild, payload);
    const attachment = new AttachmentBuilder(buffer, { name: 'welcome.png' });
    return { files: [attachment] };
  }

  const content =
    payload.content ??
    `Welcome {user} to {server}!`.replace('{user}', `<@${member.id}>`).replace('{server}', guild.name);
  return { content: renderWelcomeText(content, member, guild) };
}

async function renderWelcomeCard(
  member: GuildMember,
  guild: Guild,
  payload: WelcomePayload
): Promise<Buffer> {
  const width = 900;
  const height = 300;
  const canvas = createCanvas(width, height);
  const ctx = canvas.getContext('2d');

  ctx.fillStyle = '#111827';
  ctx.fillRect(0, 0, width, height);

  ctx.fillStyle = '#6366f1';
  ctx.fillRect(0, 0, width, 8);

  const avatar = await loadImage(member.user.displayAvatarURL({ extension: 'png', size: 128 }));
  ctx.save();
  ctx.beginPath();
  ctx.arc(120, 150, 64, 0, Math.PI * 2);
  ctx.closePath();
  ctx.clip();
  ctx.drawImage(avatar, 56, 86, 128, 128);
  ctx.restore();

  const title = payload.imageTitle ?? 'Welcome!';
  const subtitle =
    payload.imageSubtitle ?? `${member.displayName} joined ${guild.name}`;
  const plain = { mentionUser: false as const };

  ctx.fillStyle = '#f9fafb';
  ctx.font = 'bold 36px sans-serif';
  ctx.fillText(renderWelcomeText(title, member, guild, plain).slice(0, 40), 220, 130);

  ctx.fillStyle = '#d1d5db';
  ctx.font = '24px sans-serif';
  ctx.fillText(renderWelcomeText(subtitle, member, guild, plain).slice(0, 60), 220, 180);

  return canvas.toBuffer('image/png');
}

export async function sendWelcomeMessage(
  channel: TextBasedChannel,
  payload: WelcomePayload,
  member: GuildMember,
  guild: Guild
): Promise<void> {
  const message = await buildWelcomeMessage(payload, member, guild);
  if ('send' in channel) {
    await (channel as SendableChannels).send(message);
  }
}

export async function buildLeaveMessage(
  payload: LeavePayload,
  member: GuildMember,
  guild: Guild
): Promise<MessageCreateOptions> {
  if (payload.type === 'COMPONENTS_V2') {
    const componentsPayload = buildComponentsV2Payload(payload.components, {
      source: 'l',
      ref: guild.id,
      renderText: (value) => renderWelcomeText(value, member, guild)
    });
    if (componentsPayload) {
      return componentsPayload;
    }
  }

  if (payload.type === 'EMBED') {
    const embed = buildEmbedFromPayload(payload.embed, {
      renderText: (value, field) => renderWelcomeEmbedText(value, member, guild, field),
      defaultThumbnailUrl: member.user.displayAvatarURL({ size: 256 })
    });
    if (embed) {
      return { embeds: [embed] };
    }
  }

  const content = payload.content ?? '{user.tag} left {server}.';
  return { content: renderWelcomeText(content, member, guild) };
}

export async function sendLeaveMessage(
  channel: TextBasedChannel,
  payload: LeavePayload | string,
  member: GuildMember,
  guild: Guild
): Promise<void> {
  if ('send' in channel) {
    const message =
      typeof payload === 'string'
        ? { content: renderWelcomeText(payload, member, guild) }
        : await buildLeaveMessage(payload, member, guild);
    await (channel as SendableChannels).send(message);
  }
}
