import disnake
from disnake.ext import commands
from utils.forgejo_client import gitlab_client
from aiohttp import web
import logging
import json
import os
import asyncio
from typing import Dict, Any, Optional
from utils.premium import check_premium_tier

kuby_logger = logging.getLogger("KubyBot")
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# ⚡ NOUVEAU: Utilise le même fichier que gitlab_integration.py
TRACKING_FILE = os.path.join(BASE_DIR, "commandes", "gitlab_issues.json")
LEGACY_REPORTS_FILE = os.path.join(BASE_DIR, "data", "gitlab_reports.json")


def load_tracking():
    """Charge le tracking depuis gitlab_issues.json (avec migration automatique)"""
    tracking = {}
    if os.path.exists(TRACKING_FILE):
        try:
            with open(TRACKING_FILE, "r", encoding="utf-8") as f:
                tracking = json.load(f)
        except Exception as e:
            kuby_logger.error(f"Erreur chargement gitlab_issues.json: {e}")
    
    # Migration automatique depuis l'ancien fichier
    if os.path.exists(LEGACY_REPORTS_FILE):
        try:
            with open(LEGACY_REPORTS_FILE, "r", encoding="utf-8") as f:
                legacy_data = json.load(f)
            for issue_iid, user_id in legacy_data.items():
                if issue_iid not in tracking:
                    tracking[issue_iid] = {
                        "requester_id": user_id,
                        "last_note_id": 0,
                        "type": "legacy_report"
                    }
            kuby_logger.info(f"Migration automatique: {len(legacy_data)} issues fusionnées")
        except Exception as e:
            kuby_logger.error(f"Erreur migration gitlab_reports.json: {e}")
    
    return tracking


def save_tracking(data: Dict[str, Any]) -> None:
    """Sauvegarde dans gitlab_issues.json"""
    os.makedirs(os.path.dirname(TRACKING_FILE), exist_ok=True)
    temp_file = f"{TRACKING_FILE}.tmp"
    with open(temp_file, "w", encoding="utf-8") as f:
        json.dump(data, f, indent=2)
    os.replace(temp_file, TRACKING_FILE)


class BugReportModal(disnake.ui.Modal):
    def __init__(self, cog):
        self.cog = cog  # ⚡ NOUVEAU: Reçoit le cog pour tracking
        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,
            ),
        ]
        super().__init__(
            title="Signaler un Bug",
            custom_id="bug_modal",
            components=components,
        )

    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 = extract_issue_identifier(result)
            if not issue_iid:
                kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab")
                await interaction.edit_original_response(content="✅ Votre rapport a été envoyé, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
                return

            self.cog.issue_data[issue_iid] = {
                "requester_id": interaction.user.id,
                "last_note_id": 0,
                "type": "manual-report"
            }
            save_tracking(self.cog.issue_data)
            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') or result.get('html_url')})"
                )
            )
        else:
            await interaction.edit_original_response(
                content="❌ Une erreur est survenue lors de l'envoi du rapport à GitLab. Veuillez contacter un administrateur."
            )


class FeatureSuggestionModal(disnake.ui.Modal):
    def __init__(self, cog):
        self.cog = cog  # ⚡ NOUVEAU: Reçoit le cog pour tracking
        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,
            ),
        ]
        super().__init__(
            title="Suggérer une fonctionnalité",
            custom_id="suggestion_modal",
            components=components,
        )

    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 = extract_issue_identifier(result)
            if not issue_iid:
                kuby_logger.warning("Impossible de déterminer l’ID de l’issue créée depuis le retour Forgejo/GitLab")
                await interaction.edit_original_response(content="✅ Votre suggestion a été envoyée, mais l’identifiant de l’issue n’a pas pu être récupéré automatiquement.")
                return

            self.cog.issue_data[issue_iid] = {
                "requester_id": interaction.user.id,
                "last_note_id": 0,
                "type": "manual-suggestion"
            }
            save_tracking(self.cog.issue_data)
            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') or result.get('html_url')})"
                )
            )
        else:
            await interaction.edit_original_response(
                content="❌ Une erreur est survenue lors de l'envoi de la suggestion à GitLab."
            )


class BugReportView(disnake.ui.View):
    def __init__(self, cog):
        self.cog = cog  # ⚡ NOUVEAU: Reçoit le cog
        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(self.cog)
        await interaction.response.send_modal(modal)


class FeatureSuggestionView(disnake.ui.View):
    def __init__(self, cog):
        self.cog = cog  # ⚡ NOUVEAU: Reçoit le cog
        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(self.cog)
        await interaction.response.send_modal(modal)


class BugReport(commands.Cog):
    def __init__(self, bot):
        self.bot = bot
        self.issue_data = load_tracking()  # ⚡ NOUVEAU: Charge le tracking unifié

    async def cog_load(self):
        kuby_logger.info("BugReport cog chargé. Démarrage du serveur de relais interne (port 5001)...")
        REPORTS_DIR = os.path.dirname(LEGACY_REPORTS_FILE)
        os.makedirs(REPORTS_DIR, exist_ok=True)
        await self._start_webhook_server()

        # ⚡ Enregistrement des vues persistantes (boutons panel)
        # Sans ça, après un redémarrage les boutons "Remplir le formulaire"
        # dans les anciens messages de panel ne fonctionnent plus.
        self.bot.add_view(BugReportView(self))
        self.bot.add_view(FeatureSuggestionView(self))
        kuby_logger.info("✅ Vues persistantes BugReport enregistrées (open_bug_form, open_suggestion_form)")

    async def _start_webhook_server(self):
        try:
            app = web.Application()
            app.router.add_post('/bot_event', self.handle_bot_event)
            self.runner = web.AppRunner(app)
            await self.runner.setup()
            self.site = web.TCPSite(self.runner, '127.0.0.1', 5001, reuse_address=True)
            await self.site.start()
            kuby_logger.info("Internal Bot Webhook Server started on 127.0.0.1:5001")
        except Exception as e:
            kuby_logger.error(f"Failed to start Internal Bot Webhook Server: {e}")

    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):
        """Gère les webhooks (adapté pour GitLab ET Forgejo)"""
        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.")

            payload = await request.json()
            event_type = payload.get("object_kind")
            
            if event_type not in ["issue", "note"]:
                kuby_logger.info("Webhook ignoré : type d’événement non reconnu")
                return web.json_response({"status": "ignored"}, status=200)

            # Récupère l'IID de l'issue
            issue_iid = str(
                payload.get("object_attributes", {}).get("iid") or
                payload.get("issue", {}).get("iid")
            )
            
            if not issue_iid:
                kuby_logger.warning("Webhook ignoré : aucun identifiant d’issue trouvé dans le payload")
                return web.json_response({"status": "no issue id"}, status=200)
            
            issue_data = self.issue_data.get(issue_iid)
            if not issue_data:
                return web.json_response({"status": "untracked issue"}, status=200)
            
            user_id = issue_data.get("requester_id")
            if not user_id:
                return web.json_response({"status": "no requester"}, status=200)
            
            user = self.bot.get_user(user_id)
            if not user:
                try:
                    user = await self.bot.fetch_user(user_id)
                except:
                    return web.json_response({"status": "user not found"}, status=200)
            
            # 🕵️ 3. RÉCUPÉRATION DU TITRE
            issue_title = (
                payload.get("object_attributes", {}).get("title") or 
                payload.get("issue", {}).get("title", f"#{issue_iid}")
            )
            
            if event_type == "note":
                # ⚡ NOUVEAU: Notifie les commentaires via le webhook (instantané)
                note_attr = payload.get("object_attributes", {})
                is_system = note_attr.get("system", False)
                
                if not is_system:
                    note_body = (
                        note_attr.get("note") or
                        note_attr.get("body") or
                        payload.get("note", "") or ""
                    )
                    author_name = payload.get("user", {}).get("name", "Développeur")
                    
                    if note_body:
                        try:
                            embed = disnake.Embed(
                                title="💬 Nouveau commentaire sur votre signalement",
                                description=f"Le développeur a répondu à votre rapport **{issue_title}** :\n\n>>> {note_body}\n\n✍️ **Par :** {author_name}",
                                color=disnake.Color.orange()
                            )
                            embed.set_thumbnail(url=self.bot.user.display_avatar.url)
                            await user.send(embed=embed)
                            kuby_logger.info(f"Commentaire GitLab envoyé à {user} pour l'issue #{issue_iid}")
                        except (disnake.Forbidden, disnake.HTTPException) as e:
                            kuby_logger.warning(f"Impossible d'envoyer le DM à {user}: {e}")
                            if dev and dev.id != user.id:
                                try:
                                    await dev.send(f"⚠️ [DM BLOQUÉ] Impossible d'envoyer le commentaire à {user} pour l'issue #{issue_iid}")
                                except:
                                    pass
            
            elif event_type == "issue":
                # 🕵️ 5. GESTION DES CLÔTURES (Optionnel : si tu fermes le ticket sur Forgejo)
                action = payload.get("object_attributes", {}).get("action") or payload.get("action")
                state = payload.get("object_attributes", {}).get("state") or payload.get("issue", {}).get("state")
                
                is_closing_now = action in ["close", "closed"] or state == "closed"
                
                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🚀 **Prochaine étape :** La mise à jour arrive prochainement !\n✨ Merci pour votre aide !",
                            color=disnake.Color.green()
                        )
                        if self.bot.user.display_avatar:
                            embed.set_thumbnail(url=self.bot.user.display_avatar.url)
                        await user.send(embed=embed)
                    except Exception as e:
                        kuby_logger.error(f"Erreur notification clôture: {e}")

            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")
    @check_premium_tier()
    async def signifier_bug(self, interaction: disnake.ApplicationCommandInteraction):
        modal = BugReportModal(self)
        await interaction.response.send_modal(modal)

    @commands.slash_command(name="suggerer_fonctionnalite", description="Proposer une nouvelle fonctionnalité")
    @check_premium_tier()
    async def suggerer_fonctionnalite(self, interaction: disnake.ApplicationCommandInteraction):
        modal = FeatureSuggestionModal(self)
        await interaction.response.send_modal(modal)


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