import disnake
from disnake.ext import commands
from utils.gitlab_client import gitlab_client
from aiohttp import web
import logging
import json
import os
import asyncio

kuby_logger = logging.getLogger("KubyBot")
# Utilisation de chemins absolus pour la persistance après reboot
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
REPORTS_FILE = os.path.join(BASE_DIR, "data", "gitlab_reports.json")


def save_report(issue_iid, user_id):
    os.makedirs(os.path.dirname(REPORTS_FILE), exist_ok=True)
    try:
        data = {}
        if os.path.exists(REPORTS_FILE):
            try:
                with open(REPORTS_FILE, "r", encoding="utf-8") as f:
                    data = json.load(f)
            except json.JSONDecodeError:
                kuby_logger.warning("REPORTS_FILE corrupted, re-initializing to avoid tracking loss.")

        data[str(issue_iid)] = user_id

        temp_file = f"{REPORTS_FILE}.tmp"
        with open(temp_file, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=4)
        os.replace(temp_file, REPORTS_FILE)
    except Exception as e:
        kuby_logger.error(f"Error saving report to JSON: {e}")


class BugReportModal(disnake.ui.Modal):
    def __init__(self):
        super().__init__(
            title="Signaler un Bug",
            components=[
                disnake.ui.TextInput(
                    label="Titre du bug",
                    placeholder="Décrivez brièvement le problème...",
                    custom_id="bug_title",
                    required=True,
                    max_length=100,
                ),
                disnake.ui.TextInput(
                    label="Description détaillée",
                    style=disnake.TextInputStyle.paragraph,
                    placeholder="Que s'est-il passé ?",
                    custom_id="bug_description",
                    required=True,
                    max_length=1000,
                ),
            ]
        )

    async def callback(self, interaction: disnake.ModalInteraction):
        await interaction.response.send_message("Envoi de votre rapport de bug à GitLab...", ephemeral=True)

        bug_title = (interaction.text_values.get("bug_title") or "").strip()
        if not bug_title:
            bug_title = "Sans titre"

        priority_name = "Normale"
        priority_value = "Normal"

        description_value = interaction.text_values.get("bug_description") or ""

        description_text = f"**Rapporté par:** {interaction.user} ({interaction.user.id})\n"
        description_text += f"**Priorité:** {priority_name}\n\n"
        description_text += f"**Description:**\n{description_value}"

        labels = ["bug", "manual-report", f"Priority::{priority_value}"]

        result = await gitlab_client.create_issue(
            title=f"[MANUAL] {bug_title}",
            description=description_text,
            labels=labels,
        )

        if result:
            issue_iid = result.get("iid")
            save_report(issue_iid, interaction.user.id)
            await interaction.edit_original_response(
                content=(
                    "✅ Votre bug a été signalé avec succès ! "
                    "Nous avons bien été averti et le bug sera réglé dans la prochaine mise à jour. "
                    f"[Voir l'issue]({result.get('web_url')})"
                )
            )
        else:
            await interaction.edit_original_response(
                content="❌ Une erreur est survenue lors de l'envoi du rapport à GitLab. Veuillez contacter un administrateur."
            )


class BugReportView(disnake.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @disnake.ui.button(label="🎫 Remplir le formulaire", style=disnake.ButtonStyle.primary, custom_id="open_bug_form")
    async def open_bug_form(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
        modal = BugReportModal()
        await interaction.response.send_modal(modal)


class FeatureSuggestionModal(disnake.ui.Modal):
    def __init__(self):
        super().__init__(
            title="Suggérer une fonctionnalité",
            components=[
                disnake.ui.TextInput(
                    label="Titre de la suggestion",
                    placeholder="Que voulez-vous ajouter ?",
                    custom_id="suggestion_title",
                    required=True,
                    max_length=100,
                ),
                disnake.ui.TextInput(
                    label="Détails de la fonctionnalité",
                    style=disnake.TextInputStyle.paragraph,
                    placeholder="Décrivez comment cela devrait fonctionner...",
                    custom_id="suggestion_description",
                    required=True,
                    max_length=1000,
                )
            ]
        )

    async def callback(self, interaction: disnake.ModalInteraction):
        await interaction.response.send_message("Envoi de votre suggestion à GitLab...", ephemeral=True)

        suggestion_title = (interaction.text_values.get("suggestion_title") or "").strip() or "Sans titre"
        description_value = interaction.text_values.get("suggestion_description") or ""

        description_text = f"**Sugéré par:** {interaction.user} ({interaction.user.id})\n\n"
        description_text += f"**Description:**\n{description_value}"

        labels = ["enhancement", "manual-suggestion"]

        result = await gitlab_client.create_issue(
            title=f"[SUGGESTION] {suggestion_title}",
            description=description_text,
            labels=labels,
        )

        if result:
            issue_iid = result.get("iid")
            save_report(issue_iid, interaction.user.id)
            await interaction.edit_original_response(
                content=(
                    "✅ Votre suggestion a été envoyée avec succès ! "
                    "Merci de contribuer à l'amélioration du bot. "
                    f"[Voir l'issue]({result.get('web_url')})"
                )
            )
        else:
            await interaction.edit_original_response(
                content="❌ Une erreur est survenue lors de l'envoi de la suggestion à GitLab."
            )


class FeatureSuggestionView(disnake.ui.View):
    def __init__(self):
        super().__init__(timeout=None)

    @disnake.ui.button(label="🎫 Remplir le formulaire", style=disnake.ButtonStyle.green, custom_id="open_suggestion_form")
    async def open_suggestion_form(self, button: disnake.ui.Button, interaction: disnake.MessageInteraction):
        modal = FeatureSuggestionModal()
        await interaction.response.send_modal(modal)


class BugReport(commands.Cog):
    def __init__(self, bot):
        self.bot = bot

    async def cog_load(self):
        # ❌ DÉSACTIVÉ : Le webhook est géré par serveur_flask.py (port 5000)
        # Le serveur Flask proxyfie déjà les webhooks GitLab vers ce cog via /bot_event
        kuby_logger.info("BugReport cog chargé (webhook géré par serveur_flask.py)")
        # Créer le dossier pour REPORTS_FILE s'il n'existe pas
        REPORTS_DIR = os.path.dirname(REPORTS_FILE)
        os.makedirs(REPORTS_DIR, exist_ok=True)

    async def _start_webhook_server(self):
        # ❌ FONCTION DÉSACTIVÉE (voir cog_load)
        kuby_logger.warning("Tentative d'appel à _start_webhook_server() - cette fonction est désactivée")
        return

    def cog_unload(self):
        if hasattr(self, 'runner'):
            async def cleanup():
                try:
                    if hasattr(self, 'site'):
                        await self.site.stop()
                    await self.runner.cleanup()
                    kuby_logger.info("Internal Bot Webhook Server stopped and cleaned up.")
                except Exception as e:
                    kuby_logger.error(f"Error during webhook server cleanup: {e}")

            self.bot.loop.create_task(cleanup())

    async def handle_bot_event(self, request):
        provided_token = request.headers.get("X-Gitlab-Token")
        # On ignore la vérification du token pour faciliter le relais local

        try:
            if not self.bot.is_ready():
                kuby_logger.info("Webhook received but bot is not ready yet. Waiting up to 10s...")
                try:
                    await asyncio.wait_for(self.bot.wait_until_ready(), timeout=10.0)
                except asyncio.TimeoutError:
                    kuby_logger.warning("Bot still not ready after 10s. Proceeding anyway (best effort).")

            payload = await request.json()

            event_type = payload.get("object_kind")
            if event_type not in ["issue", "note"]:
                return web.json_response({"status": "ignored"}, status=200)

            if event_type == "issue":
                issue_iid = payload.get("object_attributes", {}).get("iid")
            else:
                issue_iid = payload.get("issue", {}).get("iid")

            if not issue_iid:
                return web.json_response({"status": "no issue id"}, status=200)

            if not os.path.exists(REPORTS_FILE):
                return web.json_response({"status": "no reports file"}, status=200)

            try:
                with open(REPORTS_FILE, "r", encoding="utf-8") as f:
                    reports = json.load(f)
            except json.JSONDecodeError:
                kuby_logger.error("REPORTS_FILE corrupted during read!")
                return web.json_response({"status": "corrupted file"}, status=500)

            user_id = reports.get(str(issue_iid))
            if not user_id:
                return web.json_response({"status": "untracked issue"}, status=200)

            user = self.bot.get_user(user_id)
            if not user:
                try:
                    user = await self.bot.fetch_user(user_id)
                except:
                    pass

            if not user:
                return web.json_response({"status": "user not found"}, status=200)

            # DEBUG: log brute payload minimal pour comprendre pourquoi aucun DM n'est envoyé
            kuby_logger.info(
                f"[GitLab webhook] event_type={event_type} issue_iid={issue_iid} "
                f"tracked_user_id={user_id} payload_keys={list(payload.keys())[:20]}"
            )

            if event_type == "note":
                note_obj_attrs = payload.get("object_attributes") or {}
                kuby_logger.info(
                    f"[GitLab note] system={note_obj_attrs.get('system', False)} "
                    f"note_len={len(str(note_obj_attrs.get('note') or note_obj_attrs.get('body') or payload.get('note') or ''))}"
                )

            app_info = await self.bot.application_info()
            dev = app_info.owner
            issue_title = payload.get("object_attributes", {}).get("title", f"#{issue_iid}")
            if event_type == "note":
                issue_title = payload.get("issue", {}).get("title", f"#{issue_iid}")

            if event_type == "issue":
                action = payload.get("object_attributes", {}).get("action")
                changes = payload.get("changes", {})

                if "labels" in changes:
                    curr_labels = [l.get("title") for l in changes["labels"].get("current", []) if l.get("title")]
                    display_labels = [
                        l
                        for l in curr_labels
                        if not l.startswith("Priority::") and l not in ["bug", "manual-report", "manual-suggestion"]
                    ]

                    if display_labels:
                        current_labels_str = ", ".join(display_labels)
                    else:
                        current_labels_str = "Mis à jour"

                    try:
                        embed = disnake.Embed(
                            title="🛠️ Mise à jour de votre signalement !",
                            description=(
                                f"Le statut de votre rapport **{issue_title}** a été mis à jour par l'équipe.\n\n"
                                f"📌 **Nouveaux Labels / Statuts :** {current_labels_str}"
                            ),
                            color=disnake.Color.blue()
                        )
                        embed.set_thumbnail(url=self.bot.user.display_avatar.url)

                        try:
                            await user.send(embed=embed)
                            kuby_logger.info(
                                f"Notification de label envoyée à {user} ({user.id}) pour l'issue #{issue_iid}"
                            )
                            if dev and dev.id != user.id:
                                await dev.send(
                                    f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu la notification de statut "
                                    f"**{current_labels_str}** pour l'issue #{issue_iid} ({issue_title})."
                                )
                        except (disnake.Forbidden, disnake.HTTPException) as e:
                            error_code = getattr(e, 'code', None)
                            if isinstance(e, disnake.Forbidden) or error_code == 50007:
                                kuby_logger.warning(
                                    f"Impossible d'envoyer un MP à {user} ({user.id}) - MPs désactivés (Code: {error_code})"
                                )
                                if dev and dev.id != user.id:
                                    await dev.send(
                                        f"⚠️ [DM BLOQUÉ] {user} ({user.id}) a ses MPs fermés. Impossible de notifier pour l'issue #{issue_iid}."
                                    )
                            else:
                                kuby_logger.error(f"Erreur HTTP lors de l'envoi du MP de statut à {user}: {e}")
                    except Exception as e:
                        kuby_logger.error(f"Erreur inattendue dans la notification de label : {e}")

                state = payload.get("object_attributes", {}).get("state")
                is_closing_now = action == "close" or (state == "closed" and "state_id" in changes)

                if is_closing_now:
                    try:
                        embed = disnake.Embed(
                            title="🛠️ Bug / Suggestion Terminé(e) !",
                            description=(
                                f"Bonne nouvelle ! Votre signalement **{issue_title}** a été marqué comme terminé ou résolu.\n\n"
                                f"🚀 **Prochaine étape :** La mise à jour arrive prochainement (ou est déjà là) !\n"
                                f"✨ Merci pour votre aide !"
                            ),
                            color=disnake.Color.green()
                        )
                        embed.set_thumbnail(url=self.bot.user.display_avatar.url)

                        try:
                            await user.send(embed=embed)
                            kuby_logger.info(
                                f"Notification de clôture envoyée à {user} ({user.id}) pour l'issue #{issue_iid}"
                            )
                            if dev and dev.id != user.id:
                                await dev.send(
                                    f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu la notification de CLÔTURE pour l'issue #{issue_iid}."
                                )
                        except (disnake.Forbidden, disnake.HTTPException) as e:
                            error_code = getattr(e, 'code', None)
                            if isinstance(e, disnake.Forbidden) or error_code == 50007:
                                kuby_logger.warning(f"Impossible d'envoyer le MP de clôture à {user} ({user.id}) - MPs désactivés.")
                                if dev and dev.id != user.id:
                                    await dev.send(
                                        f"⚠️ [DM BLOQUÉ] Impossible d'annoncer la clôture à {user} ({user.id}) pour l'issue #{issue_iid}."
                                    )
                            else:
                                kuby_logger.error(f"Erreur HTTP lors de l'envoi du MP de clôture à {user}: {e}")
                    except Exception as e:
                        kuby_logger.error(f"Erreur inattendue dans la notification de clôture : {e}")

            elif event_type == "note":
                note_attr = payload.get("object_attributes", {})
                is_system = note_attr.get("system", False)

                kuby_logger.info(
                    f"[GitLab note] dispatch started issue_iid={issue_iid} is_system={is_system} "
                    f"note_field_present={bool(note_attr.get('note') or note_attr.get('body'))}"
                )

                if not is_system:
                    note_body = (
                        note_attr.get("note")
                        or note_attr.get("body")
                        or payload.get("note", "")
                        or payload.get("object_attributes", {}).get("note", "")
                        or ""
                    )
                    author_name = payload.get("user", {}).get("name", "Développeur")

                    try:
                        embed = disnake.Embed(
                            title="💬 Nouveau commentaire sur votre signalement",
                            description=(
                                f"Le développeur a répondu à votre rapport **{issue_title}** :\n\n"
                                f">>> {note_body}\n\n"
                                f"✍️ **Par :** {author_name}"
                            ),
                            color=disnake.Color.orange()
                        )
                        embed.set_thumbnail(url=self.bot.user.display_avatar.url)

                        try:
                            await user.send(embed=embed)
                            kuby_logger.info(
                                f"Commentaire GitLab envoyé à {user} ({user.id}) pour l'issue #{issue_iid}"
                            )
                            if dev and dev.id != user.id:
                                await dev.send(
                                    f"✅ [SUIVI] L'utilisateur {user} ({user.id}) a bien reçu votre commentaire pour l'issue #{issue_iid}."
                                )
                        except (disnake.Forbidden, disnake.HTTPException):
                            if dev and dev.id != user.id:
                                try:
                                    await dev.send(
                                        f"⚠️ [DM BLOQUÉ] Impossible d'envoyer votre commentaire à {user} ({user.id}) pour l'issue #{issue_iid} (DMs désactivés)."
                                    )
                                except (disnake.Forbidden, disnake.HTTPException):
                                    pass  # On ne peut pas envoyer au dev non plus, on abandonne
                    except Exception as e:
                        kuby_logger.error(
                            f"Erreur inattendue dans la notification de commentaire : {e}",
                            exc_info=True,
                        )

            return web.json_response({"status": "success"}, status=200)

        except Exception as e:
            kuby_logger.error(f"Error handling bot event: {e}")
            return web.json_response({"status": "error", "message": str(e)}, status=500)

    @commands.slash_command(
        name="signaler_bug",
        description="Signaler un bug aux développeurs",
    )
    async def signifier_bug(self, interaction: disnake.ApplicationCommandInteraction):
        """Ouvre un formulaire pour signaler un bug."""
        modal = BugReportModal()
        await interaction.response.send_modal(modal)

    @commands.slash_command(
        name="suggerer_fonctionnalite",
        description="Proposer une nouvelle fonctionnalité pour le bot",
    )
    async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
        """Ouvre un formulaire pour suggérer une fonctionnalité."""
        modal = FeatureSuggestionModal()
        await interaction.response.send_modal(modal)


def setup(bot):
    bot.add_cog(BugReport(bot))