import {
  ActionRowBuilder,
  ButtonBuilder,
  ButtonInteraction,
  ButtonStyle,
  Client,
  EmbedBuilder,
  ModalBuilder,
  TextInputBuilder,
  TextInputStyle,
  ModalSubmitInteraction,
  GuildMember
} from 'discord.js';
import { prisma } from '../database';
import { settingsStore } from '../config/state';
import { env } from '../config/env';

export class RegisterService {
  private client: Client | null = null;

  public setClient(client: Client) {
    this.client = client;
  }

  public async listForms(guildId: string) {
    return prisma.registerForm.findMany({ where: { guildId }, include: { fields: { orderBy: { order: 'asc' } } }, orderBy: { createdAt: 'desc' } });
  }

  public async saveForm(form: {
    id?: string;
    guildId: string;
    name: string;
    description?: string;
    reviewChannelId?: string;
    notifyRoleIds?: string[];
    isActive?: boolean;
    fields: { id?: string; label: string; type: string; required?: boolean; order?: number }[];
  }) {
    const notify = (form.notifyRoleIds || []).filter(Boolean);
    if (form.id) {
      await prisma.registerForm.update({
        where: { id: form.id },
        data: {
          name: form.name,
          description: form.description,
          reviewChannelId: form.reviewChannelId,
          notifyRoleIds: notify,
          isActive: form.isActive ?? true
        }
      });
      await prisma.registerFormField.deleteMany({ where: { formId: form.id } });
      await prisma.registerFormField.createMany({
        data: (form.fields || []).map((f, idx) => ({
          formId: form.id as string,
          label: f.label,
          type: f.type,
          required: f.required ?? false,
          order: f.order ?? idx
        }))
      });
      return prisma.registerForm.findUnique({ where: { id: form.id }, include: { fields: { orderBy: { order: 'asc' } } } });
    }
    const created = await prisma.registerForm.create({
      data: {
        guildId: form.guildId,
        name: form.name,
        description: form.description,
        reviewChannelId: form.reviewChannelId,
        notifyRoleIds: notify,
        isActive: form.isActive ?? true,
        fields: {
          create: (form.fields || []).map((f, idx) => ({
            label: f.label,
            type: f.type,
            required: f.required ?? false,
            order: f.order ?? idx
          }))
        }
      },
      include: { fields: { orderBy: { order: 'asc' } } }
    });
    return created;
  }

  public async deleteForm(guildId: string, id: string) {
    const form = await prisma.registerForm.findFirst({ where: { id, guildId } });
    if (!form) return false;
    await prisma.registerFormField.deleteMany({ where: { formId: id } });
    await prisma.registerForm.delete({ where: { id } });
    return true;
  }

  public async sendPanel(guildId: string, formId: string, channelId?: string, message?: string) {
    if (!this.client) return null;
    const form = await prisma.registerForm.findFirst({ where: { id: formId, guildId }, include: { fields: true } });
    if (!form) return null;
    const targetChannelId = channelId || form.reviewChannelId || settingsStore.get(guildId)?.registerConfig?.reviewChannelId;
    if (!targetChannelId) return null;
    const guild = this.client.guilds.cache.get(guildId) ?? (await this.client.guilds.fetch(guildId).catch(() => null));
    if (!guild) return null;
    const channel = await guild.channels.fetch(targetChannelId).catch(() => null);
    if (!channel || !channel.isTextBased()) return null;
    const embed = new EmbedBuilder()
      .setTitle(form.name)
      .setDescription(message || 'Klicke auf Registrieren, um das Formular auszufüllen.')
      .setColor(0xf97316);
    const btn = new ButtonBuilder().setCustomId(`register:form:${form.id}`).setLabel('Registrieren').setStyle(ButtonStyle.Primary);
    const row = new ActionRowBuilder<ButtonBuilder>().addComponents(btn);
    const sent = await (channel as any).send({ embeds: [embed], components: [row] });
    return sent.id;
  }

  public async handleButton(interaction: ButtonInteraction) {
    if (interaction.customId.startsWith('register:form:')) {
      const formId = interaction.customId.split(':')[2];
      const form = await prisma.registerForm.findFirst({ where: { id: formId }, include: { fields: { orderBy: { order: 'asc' } } } });
      if (!form) return interaction.reply({ content: 'Formular nicht gefunden.', ephemeral: true });
      const modal = new ModalBuilder().setTitle(form.name).setCustomId(`register:submit:${form.id}`);
      const components: any[] = [];
      form.fields.slice(0, 5).forEach((f) => {
        const input = new TextInputBuilder()
          .setCustomId(f.id)
          .setLabel(f.label.slice(0, 45) || 'Feld')
          .setStyle(f.type === 'longText' ? TextInputStyle.Paragraph : TextInputStyle.Short)
          .setRequired(f.required ?? false);
        components.push(new ActionRowBuilder<TextInputBuilder>().addComponents(input));
      });
      modal.addComponents(components as any);
      await interaction.showModal(modal);
      return;
    }

    if (interaction.customId.startsWith('register:review:')) {
      const [, , action, appId] = interaction.customId.split(':');
      const app = await prisma.registerApplication.findUnique({ where: { id: appId }, include: { form: true } });
      if (!app) {
        await interaction.reply({ content: 'Antrag nicht gefunden.', ephemeral: true });
        return;
      }
      const statusMap: any = { accept: 'accepted', invite: 'invited', reject: 'rejected' };
      const newStatus = statusMap[action] || 'pending';
      const updated = await prisma.registerApplication.update({
        where: { id: appId },
        data: { status: newStatus, reviewedBy: interaction.user.id }
      });
      await this.updateReviewMessage(interaction, updated);
      const user = await this.client?.users.fetch(app.userId).catch(() => null);
      if (user) {
        const msg =
          newStatus === 'accepted'
            ? 'Deine Registrierung wurde akzeptiert.'
            : newStatus === 'invited'
            ? 'Bitte komm für ein Gespräch vorbei.'
            : 'Deine Registrierung wurde abgelehnt.';
        user.send(msg).catch(() => undefined);
      }
      await interaction.reply({ content: 'Status aktualisiert.', ephemeral: true });
      return;
    }
  }

  public async handleModal(interaction: ModalSubmitInteraction) {
    if (!interaction.customId.startsWith('register:submit:')) return;
    const formId = interaction.customId.split(':')[2];
    const form = await prisma.registerForm.findFirst({
      where: { id: formId },
      include: { fields: { orderBy: { order: 'asc' } } }
    });
    if (!form) {
      await interaction.reply({ content: 'Formular nicht gefunden.', ephemeral: true });
      return;
    }
    const answersPayload = form.fields.map((f) => ({
      fieldId: f.id,
      value: interaction.fields.getTextInputValue(f.id) || ''
    }));
    const app = await prisma.registerApplication.create({
      data: {
        guildId: interaction.guildId ?? '',
        userId: interaction.user.id,
        formId: form.id,
        status: 'pending',
        answers: {
          create: answersPayload
        }
      },
      include: { answers: true }
    });
    await interaction.reply({ content: 'Registrierung gesendet.', ephemeral: true });
    await this.postReviewEmbed(form, app, interaction.user.id, interaction.guildId || '');
  }

  private async postReviewEmbed(form: any, app: any, userId: string, guildId: string) {
    if (!this.client) return;
    const cfg = settingsStore.get(guildId);
    const channelId = form.reviewChannelId || cfg?.registerConfig?.reviewChannelId;
    if (!channelId) return;
    const guild = this.client.guilds.cache.get(guildId) ?? (await this.client.guilds.fetch(guildId).catch(() => null));
    if (!guild) return;
    const channel = await guild.channels.fetch(channelId).catch(() => null);
    if (!channel || !channel.isTextBased()) return;
    const member = await guild.members.fetch(userId).catch(() => null);
    const fields = await prisma.registerFormField.findMany({ where: { formId: form.id }, orderBy: { order: 'asc' } });
    const answers = await prisma.registerApplicationAnswer.findMany({ where: { applicationId: app.id } });
    const embed = new EmbedBuilder()
      .setTitle(`Registrierung: ${form.name}`)
      .setDescription(form.description || '')
      .setColor(0xf97316)
      .addFields(
        ...fields.map((f) => ({
          name: f.label,
          value: answers.find((a) => a.fieldId === f.id)?.value || '-',
          inline: false
        }))
      )
      .setFooter({ text: `Status: ${app.status}` })
      .setTimestamp(new Date(app.createdAt));
    if (member) embed.setAuthor({ name: member.user.tag, iconURL: member.user.displayAvatarURL() });
    const row = new ActionRowBuilder<ButtonBuilder>().addComponents(
      new ButtonBuilder().setCustomId(`register:review:accept:${app.id}`).setLabel('Akzeptieren').setStyle(ButtonStyle.Success),
      new ButtonBuilder().setCustomId(`register:review:invite:${app.id}`).setLabel('Gespräch einladen').setStyle(ButtonStyle.Primary),
      new ButtonBuilder().setCustomId(`register:review:reject:${app.id}`).setLabel('Ablehnen').setStyle(ButtonStyle.Danger)
    );
    const notifyRoles = form.notifyRoleIds || cfg?.registerConfig?.notifyRoleIds || [];
    const content = notifyRoles.length ? notifyRoles.map((id: string) => `<@&${id}>`).join(' ') : null;
    await (channel as any).send({ content: content || undefined, embeds: [embed], components: [row] });
  }

  private async updateReviewMessage(interaction: ButtonInteraction, app: any) {
    if (!interaction.message || !interaction.message.editable) return;
    const embed = (interaction.message.embeds?.[0] as any) ?? null;
    if (embed) {
      embed.data = { ...(embed.data || {}), footer: { text: `Status: ${app.status} | Reviewer: ${interaction.user.tag}` } };
    }
    const components = interaction.message.components;
    await interaction.message.edit({ embeds: embed ? [embed] : interaction.message.embeds, components });
  }

  public async listApplications(guildId: string, status?: string, formId?: string) {
    const where: any = { guildId };
    if (status) where.status = status;
    if (formId) where.formId = formId;
    return prisma.registerApplication.findMany({
      where,
      orderBy: { createdAt: 'desc' },
      include: { form: true }
    });
  }

  public async getApplication(id: string) {
    return prisma.registerApplication.findUnique({
      where: { id },
      include: { form: true, answers: true }
    });
  }
}
