package com.tiedup.remake.core;

import com.mojang.logging.LogUtils;
import com.tiedup.remake.commands.TiedUpCommand;
import com.tiedup.remake.compat.mca.MCACompat;
import com.tiedup.remake.dispenser.DispenserBehaviors;
import com.tiedup.remake.entities.ModEntities;
import com.tiedup.remake.items.ModCreativeTabs;
import com.tiedup.remake.items.ModItems;
import com.tiedup.remake.network.ModNetwork;
import com.tiedup.remake.util.ModGameRules;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.server.ServerStartingEvent;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.slf4j.Logger;

/**
 * TiedUp! - Main Mod Class
 *
 * Community remake of the TiedUp! mod for Minecraft 1.20.1
 * Original mod by Yuti & Marl Velius (1.12.2)
 *
 * This is an independent community remake, not affiliated with the original developers.
 * For educational and preservation purposes.
 *
 * @author Unknown
 * @version 0.1.0-ALPHA
 */
@Mod(TiedUpMod.MOD_ID)
public class TiedUpMod {

    // Mod ID - Must match gradle.properties
    public static final String MOD_ID = "tiedup";

    // Logger
    public static final Logger LOGGER = LogUtils.getLogger();

    @SuppressWarnings("removal") // FMLJavaModLoadingContext.get() is correct for 1.20.1, deprecated in 1.21.1+
    public TiedUpMod() {
        IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();

        // Register items
        ModItems.ITEMS.register(modEventBus);

        com.tiedup.remake.blocks.ModBlocks.BLOCKS.register(modEventBus);
        com.tiedup.remake.blocks.ModBlocks.BLOCK_ITEMS.register(modEventBus);
        com.tiedup.remake.blocks.entity.ModBlockEntities.BLOCK_ENTITIES.register(
            modEventBus
        );

        // V2 System: Register V2 blocks and block entities (OBJ models)
        com.tiedup.remake.v2.V2Blocks.BLOCKS.register(modEventBus);
        com.tiedup.remake.v2.V2Items.ITEMS.register(modEventBus);
        com.tiedup.remake.v2.V2BlockEntities.BLOCK_ENTITIES.register(
            modEventBus
        );

        // V2 bondage items
        com.tiedup.remake.v2.bondage.V2BondageItems.ITEMS.register(modEventBus);

        // Register mob effects
        ModEffects.MOB_EFFECTS.register(modEventBus);

        // Register sounds
        ModSounds.SOUND_EVENTS.register(modEventBus);

        // Register creative tabs
        ModCreativeTabs.CREATIVE_MODE_TABS.register(modEventBus);

        ModEntities.ENTITIES.register(modEventBus);

        // Register menu types (vanilla containers)
        ModMenuTypes.MENUS.register(modEventBus);

        // Register structure processors
        com.tiedup.remake.worldgen.ModProcessors.PROCESSORS.register(
            modEventBus
        );

        // Register structures
        com.tiedup.remake.worldgen.ModStructures.STRUCTURE_TYPES.register(
            modEventBus
        );
        com.tiedup.remake.worldgen.ModStructures.STRUCTURE_PIECE_TYPES.register(
            modEventBus
        );

        // Register network packets
        ModNetwork.register();

        // Register Config
        net.minecraftforge.fml.ModLoadingContext.get().registerConfig(
            net.minecraftforge.fml.config.ModConfig.Type.SERVER,
            ModConfig.SERVER_SPEC
        );
        net.minecraftforge.fml.ModLoadingContext.get().registerConfig(
            net.minecraftforge.fml.config.ModConfig.Type.CLIENT,
            ModConfig.CLIENT_SPEC
        );

        ModGameRules.register();

        // Register the commonSetup method for modloading
        modEventBus.addListener(this::commonSetup);

        // Register ourselves for server and other game events we are interested in
        MinecraftForge.EVENT_BUS.register(this);

        LOGGER.info("TiedUp! Mod initializing...");
        LOGGER.info(
            "This is a community remake - Original mod by Yuti & Marl Velius"
        );
    }

    /**
     * Common setup - runs on both client and server
     */
    private void commonSetup(final FMLCommonSetupEvent event) {
        LOGGER.info("TiedUp! Common setup");
        LOGGER.info("Registered {} items", ModItems.ITEMS.getEntries().size());

        // Skin loading moved to SkinReloadListener (registered via AddReloadListenerEvent)
        // This allows skins to be loaded from datapacks and reloaded with /reload

        com.tiedup.remake.util.tasks.SaleLoader.init();
        com.tiedup.remake.util.tasks.JobLoader.init();

        // MCA Compatibility: Initialize if MCA is present
        MCACompat.init();
        com.tiedup.remake.compat.wildfire.WildfireCompat.init();

        // Register dispenser behaviors (must be on main thread)
        event.enqueueWork(DispenserBehaviors::register);

        // RIG Phase 3 — force class-load des motions pour assigner les
        // universalOrdinal() via ExtendableEnumManager (init lazy JLS sinon).
        //
        // ORDER MATTERS (review RISK-001 on P3-01 commit 15e405f) : LivingMotions
        // vanilla EF doit etre class-loaded AVANT TiedUpLivingMotions, sinon nos
        // ordinals prennent 0..N, puis les vanilla arriveraient plus tard avec
        // les memes ordinals -> collision silencieuse. Les patches EF ne
        // garantissent pas que LivingMotions soit touche avant ce hook, donc on
        // le force explicitement ici.
        com.tiedup.remake.rig.anim.LivingMotions.values();
        com.tiedup.remake.rig.anim.TiedUpLivingMotions.values();

        // RIG Phase 2 — dispatcher EntityType → EntityPatch (PLAYER Phase 2, NPCs Phase 5)
        event.enqueueWork(com.tiedup.remake.rig.patch.EntityPatchProvider::registerEntityPatches);

        // RIG Phase 2.7 — registre des StaticAnimation (CONTEXT_STAND_IDLE).
        // Placeholder JSON procédural jusqu'à ce que les assets Blender arrivent
        // (cf. docs/plans/rig/ASSETS_NEEDED.md).
        event.enqueueWork(com.tiedup.remake.rig.TiedUpAnimationRegistry::initStaticAnimations);
    }

    /**
     * Server starting event
     */
    @SubscribeEvent
    public void onServerStarting(ServerStartingEvent event) {
        LOGGER.info("TiedUp! Server starting");

        // Register all commands under /tiedup
        TiedUpCommand.register(event.getServer().getCommands().getDispatcher());
        LOGGER.info(
            "Registered all TiedUp commands (all commands now under /tiedup)"
        );

        // Initialize PrisonerManager
        try {
            net.minecraft.server.level.ServerLevel overworld = event
                .getServer()
                .overworld();
            // Force initialization of PrisonerManager
            com.tiedup.remake.prison.PrisonerManager.get(overworld);
            LOGGER.info("PrisonerManager initialized");
        } catch (Exception e) {
            LOGGER.error(
                "Error during PrisonerManager initialization: {}",
                e.getMessage(),
                e
            );
        }
    }

    /**
     * Client-side setup (MOD bus events)
     */
    @Mod.EventBusSubscriber(
        modid = MOD_ID,
        bus = Mod.EventBusSubscriber.Bus.MOD,
        value = Dist.CLIENT
    )
    public static class ClientModEvents {

        @SubscribeEvent
        public static void onClientSetup(FMLClientSetupEvent event) {
            LOGGER.info("TiedUp! Client setup");

            // Initialize animation system
            event.enqueueWork(() -> {
                // RIG Phase 2 — override client dispatch PLAYER → Local/Client/ServerPlayerPatch
                com.tiedup.remake.rig.patch.EntityPatchProvider.registerEntityPatchesClient();

                // Phase 2.8 RIG cleanup : BondageAnimationManager.init() (factory
                // registrations PlayerAnimator côté joueur) a été supprimé — le RIG
                // prend le relai pour les joueurs via RigAnimationTickHandler.
                // Les NPCs continuent d'être animés via BondageAnimationManager en
                // accès direct animation stack (cf. NpcAnimationTickHandler).

                // Initialize OBJ model registry for 3D bondage items
                com.tiedup.remake.client.renderer.obj.ObjModelRegistry.init();

                // Register menu screens (vanilla container system)
                net.minecraft.client.gui.screens.MenuScreens.register(
                    ModMenuTypes.NPC_INVENTORY.get(),
                    com.tiedup.remake.client.gui.screens.NpcInventoryScreen::new
                );
                LOGGER.info("Menu screens registered");

                // Note: SkinManagers are loaded server-side via SkinReloadListener
                // Properties (variant ID, hasSlimArms) are synced to clients via entityData
                // Clients compute texture paths from the synced variant ID
            });
        }

        @SubscribeEvent
        public static void onRegisterKeybindings(
            net.minecraftforge.client.event.RegisterKeyMappingsEvent event
        ) {
            com.tiedup.remake.client.ModKeybindings.register(event);
        }

        /**
         * Register entity renderers.
         */
        @SubscribeEvent
        public static void onRegisterRenderers(
            net.minecraftforge.client.event.EntityRenderersEvent.RegisterRenderers event
        ) {
            event.registerEntityRenderer(
                ModEntities.DAMSEL.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityDamsel");

            event.registerEntityRenderer(
                ModEntities.DAMSEL_SHINY.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityDamselShiny");

            event.registerEntityRenderer(
                ModEntities.KIDNAPPER.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityKidnapper");

            event.registerEntityRenderer(
                ModEntities.KIDNAPPER_ELITE.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityKidnapperElite");

            // EntityKidnapperMerchant renderer (reuses DamselRenderer)
            event.registerEntityRenderer(
                ModEntities.KIDNAPPER_MERCHANT.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info(
                "Registered entity renderer for EntityKidnapperMerchant"
            );

            event.registerEntityRenderer(
                ModEntities.KIDNAPPER_ARCHER.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityKidnapperArcher");

            // EntitySlaveTrader renderer (reuses DamselRenderer)
            event.registerEntityRenderer(
                ModEntities.SLAVE_TRADER.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntitySlaveTrader");

            // EntityMaid renderer (reuses DamselRenderer)
            event.registerEntityRenderer(
                ModEntities.MAID.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityMaid");

            // EntityMaster renderer (reuses DamselRenderer)
            event.registerEntityRenderer(
                ModEntities.MASTER.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityMaster");

            // EntityLaborGuard renderer (reuses DamselRenderer)
            event.registerEntityRenderer(
                ModEntities.LABOR_GUARD.get(),
                com.tiedup.remake.client.renderer.DamselRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityLaborGuard");

            event.registerEntityRenderer(
                ModEntities.ROPE_ARROW.get(),
                com.tiedup.remake.client.renderer.RopeArrowRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityRopeArrow");

            event.registerEntityRenderer(
                ModEntities.KIDNAP_BOMB_ENTITY.get(),
                com.tiedup.remake.client.renderer.KidnapBombRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityKidnapBomb");

            // NPC Fishing Bobber renderer (textured quad)
            event.registerEntityRenderer(
                ModEntities.NPC_FISHING_BOBBER.get(),
                com.tiedup.remake.client.renderer.NpcFishingBobberRenderer::new
            );
            LOGGER.info("Registered entity renderer for NpcFishingBobber");

            // Furniture entity renderer (data-driven GLB mesh rendering)
            event.registerEntityRenderer(
                ModEntities.FURNITURE.get(),
                com.tiedup.remake.v2.furniture.client
                    .FurnitureEntityRenderer::new
            );
            LOGGER.info("Registered entity renderer for EntityFurniture");

            event.registerBlockEntityRenderer(
                com.tiedup.remake.blocks.entity.ModBlockEntities.TRAPPED_CHEST.get(),
                net.minecraft.client.renderer.blockentity.ChestRenderer::new
            );
            LOGGER.info("Registered block entity renderer for TrappedChest");
        }

        /**
         * Register layer definitions.
         */
        @SubscribeEvent
        public static void onRegisterLayerDefinitions(
            net.minecraftforge.client.event.EntityRenderersEvent.RegisterLayerDefinitions event
        ) {
            event.registerLayerDefinition(
                com.tiedup.remake.client.renderer.models.BondageLayerDefinitions.BONDAGE_LAYER,
                com.tiedup.remake.client.renderer.models
                    .BondageLayerDefinitions::createBodyLayer
            );
            event.registerLayerDefinition(
                com.tiedup.remake.client.renderer.models.BondageLayerDefinitions.BONDAGE_LAYER_SLIM,
                com.tiedup.remake.client.renderer.models
                    .BondageLayerDefinitions::createSlimBodyLayer
            );
            LOGGER.info("Registered BondageLayerDefinitions (normal + slim)");

            // No custom layer registration needed - DamselModel extends PlayerModel
            LOGGER.info("EntityDamsel uses vanilla PLAYER model layers");
        }

        /**
         * Add render layers to entity renderers.
         *
         * Uses LOW priority to ensure bondage layers are added AFTER Wildfire's
         * breast layers (which use default NORMAL priority). This ensures bondage
         * items render ON TOP of breasts for players.
         */
        @SubscribeEvent(
            priority = net.minecraftforge.eventbus.api.EventPriority.LOW
        )
        public static void onAddLayers(
            net.minecraftforge.client.event.EntityRenderersEvent.AddLayers event
        ) {
            // Initialize ClothesModelCache for clothes rendering
            com.tiedup.remake.client.renderer.layers.ClothesModelCache.init(
                event.getEntityModels()
            );

            // V1 render layers (BondageItemRenderLayer, ArmorStandBondageLayer) removed.
            // V2 render layer handles all equipment rendering.

            // MCA Compatibility: Add bondage render layers to MCA villager renderers
            com.tiedup.remake.compat.mca.MCACompat.registerRenderLayers(event);

            // Wildfire Compatibility: Add gender layers
            com.tiedup.remake.compat.wildfire.WildfireCompat.registerRenderLayers(
                event
            );
        }
    }

    /**
     * Common MOD bus events (runs on both client and server)
     */
    @Mod.EventBusSubscriber(
        modid = MOD_ID,
        bus = Mod.EventBusSubscriber.Bus.MOD
    )
    public static class CommonModEvents {

        /**
         * Register spawn placements for natural spawning.
         * All NPCs spawn on land like other creatures.
         */
        @SubscribeEvent
        public static void onRegisterSpawnPlacements(
            net.minecraftforge.event.entity.SpawnPlacementRegisterEvent event
        ) {
            // Use Mob::checkMobSpawnRules for PathfinderMob entities
            event.register(
                ModEntities.DAMSEL.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info("Registered spawn placement for EntityDamsel");

            event.register(
                ModEntities.KIDNAPPER.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info("Registered spawn placement for EntityKidnapper");

            event.register(
                ModEntities.KIDNAPPER_ELITE.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info("Registered spawn placement for EntityKidnapperElite");

            event.register(
                ModEntities.KIDNAPPER_ARCHER.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info("Registered spawn placement for EntityKidnapperArcher");

            event.register(
                ModEntities.KIDNAPPER_MERCHANT.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info(
                "Registered spawn placement for EntityKidnapperMerchant"
            );

            event.register(
                ModEntities.LABOR_GUARD.get(),
                net.minecraft.world.entity.SpawnPlacements.Type.ON_GROUND,
                net.minecraft.world.level.levelgen.Heightmap.Types.MOTION_BLOCKING_NO_LEAVES,
                net.minecraft.world.entity.Mob::checkMobSpawnRules,
                net.minecraftforge.event.entity.SpawnPlacementRegisterEvent.Operation.REPLACE
            );
            LOGGER.info("Registered spawn placement for EntityLaborGuard");
        }

        /**
         * Register entity attributes.
         */
        @SubscribeEvent
        public static void onEntityAttributeCreation(
            net.minecraftforge.event.entity.EntityAttributeCreationEvent event
        ) {
            event.put(
                ModEntities.DAMSEL.get(),
                com.tiedup.remake.entities.EntityDamsel.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityDamsel");

            event.put(
                ModEntities.DAMSEL_SHINY.get(),
                com.tiedup.remake.entities.EntityDamselShiny.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityDamselShiny");

            event.put(
                ModEntities.KIDNAPPER.get(),
                com.tiedup.remake.entities.EntityKidnapper.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityKidnapper");

            event.put(
                ModEntities.KIDNAPPER_ELITE.get(),
                com.tiedup.remake.entities.EntityKidnapperElite.createAttributes().build()
            );
            LOGGER.info(
                "Registered entity attributes for EntityKidnapperElite"
            );

            // EntityKidnapperMerchant attributes
            event.put(
                ModEntities.KIDNAPPER_MERCHANT.get(),
                com.tiedup.remake.entities.EntityKidnapperMerchant.createAttributes().build()
            );
            LOGGER.info(
                "Registered entity attributes for EntityKidnapperMerchant"
            );

            event.put(
                ModEntities.KIDNAPPER_ARCHER.get(),
                com.tiedup.remake.entities.EntityKidnapperArcher.createAttributes().build()
            );
            LOGGER.info(
                "Registered entity attributes for EntityKidnapperArcher"
            );

            // Slave Trader & Maid System: EntitySlaveTrader attributes
            event.put(
                ModEntities.SLAVE_TRADER.get(),
                com.tiedup.remake.entities.EntitySlaveTrader.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntitySlaveTrader");

            // Slave Trader & Maid System: EntityMaid attributes
            event.put(
                ModEntities.MAID.get(),
                com.tiedup.remake.entities.EntityMaid.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityMaid");

            // Master NPC: EntityMaster attributes (pet play system)
            event.put(
                ModEntities.MASTER.get(),
                com.tiedup.remake.entities.EntityMaster.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityMaster");

            // Labor Guard: EntityLaborGuard attributes
            event.put(
                ModEntities.LABOR_GUARD.get(),
                com.tiedup.remake.entities.EntityLaborGuard.createAttributes().build()
            );
            LOGGER.info("Registered entity attributes for EntityLaborGuard");
        }
    }

    /**
     * Common events registered on the FORGE event bus.
     * These events are triggered by Forge/Minecraft, not during mod initialization.
     */
    @Mod.EventBusSubscriber(
        modid = MOD_ID,
        bus = Mod.EventBusSubscriber.Bus.FORGE
    )
    public static class ForgeEvents {

        /**
         * Register reload listeners for data-driven systems.
         *
         * - SkinReloadListener loads skin definitions from JSON files
         * - Triggers on server start and /reload command
         *
         * Personality System: Data-driven dialogue
         * - DialogueReloadListener loads dialogue JSON files from assets
         */
        @SubscribeEvent
        public static void onAddReloadListeners(
            net.minecraftforge.event.AddReloadListenerEvent event
        ) {
            event.addListener(
                new com.tiedup.remake.entities.skins.SkinReloadListener()
            );
            LOGGER.info(
                "Registered SkinReloadListener for data-driven skin loading"
            );

            event.addListener(
                new com.tiedup.remake.dialogue.DialogueReloadListener()
            );
            LOGGER.info(
                "Registered DialogueReloadListener for data-driven dialogue loading"
            );

            // Data-driven bondage item definitions (server-side, from data/<namespace>/tiedup_items/)
            event.addListener(
                new com.tiedup.remake.v2.bondage.datadriven.DataDrivenItemServerReloadListener()
            );
            LOGGER.info(
                "Registered DataDrivenItemServerReloadListener for server-side item definitions"
            );

            // Data-driven furniture definitions (server-side, from data/<namespace>/tiedup_furniture/)
            event.addListener(
                new com.tiedup.remake.v2.furniture.FurnitureServerReloadListener()
            );
            LOGGER.info(
                "Registered FurnitureServerReloadListener for data-driven furniture definitions"
            );

            // Data-driven room theme definitions (server-side, from data/<namespace>/tiedup_room_themes/)
            event.addListener(
                new com.tiedup.remake.worldgen.RoomThemeReloadListener()
            );
            LOGGER.info(
                "Registered RoomThemeReloadListener for data-driven room themes"
            );
        }
    }
}
