use pumpkin_data::Block;
use pumpkin_util::{
    BlockDirection,
    math::block_box::BlockBox,
    random::{RandomGenerator, RandomImpl},
};

use crate::{
    ProtoChunk,
    generation::structure::{
        piece::StructurePieceType,
        structures::{
            StructurePiece, StructurePieceBase, StructurePiecesCollector,
            stronghold::{
                EntranceType, PieceWeight, StoneBrickRandomizer, StrongholdPiece,
                StrongholdPieceType,
            },
        },
    },
};

use crate::world::WorldPortalExt;

pub struct RightTurnPiece {
    pub piece: StrongholdPiece,
}

impl RightTurnPiece {
    pub fn create(
        collector: &mut StructurePiecesCollector,
        random: &mut impl RandomImpl,
        x: i32,
        y: i32,
        z: i32,
        orientation: BlockDirection,
        chain_length: u32,
    ) -> Option<Box<dyn StructurePieceBase>> {
        // 5x5x5 box
        let bounding_box = BlockBox::rotated(x, y, z, -1, -1, 0, 5, 5, 5, &orientation);

        if !StrongholdPiece::is_in_bounds(&bounding_box)
            || collector.get_intersecting(&bounding_box).is_some()
        {
            return None;
        }

        let mut piece = StrongholdPiece::new(
            StructurePieceType::StrongholdRightTurn,
            chain_length,
            bounding_box,
        );
        piece.piece.set_facing(Some(orientation));
        piece.entry_door = EntranceType::get_random(random);

        Some(Box::new(Self { piece }))
    }
}

impl StructurePieceBase for RightTurnPiece {
    fn as_any(&self) -> &dyn std::any::Any {
        self
    }
    fn get_structure_piece(&self) -> &StructurePiece {
        &self.piece.piece
    }

    fn get_structure_piece_mut(&mut self) -> &mut StructurePiece {
        &mut self.piece.piece
    }

    fn fill_openings(
        &self,
        start: &StructurePiece,
        random: &mut RandomGenerator,
        weights: &mut Vec<PieceWeight>,
        last_piece_type: &mut Option<StrongholdPieceType>,
        _has_portal_room: &mut bool,

        collector: &mut StructurePiecesCollector,
        pieces_to_process: &mut Vec<Box<dyn StructurePieceBase>>,
    ) {
        let facing = self.piece.piece.facing.unwrap_or(BlockDirection::North);

        if facing == BlockDirection::North || facing == BlockDirection::East {
            self.piece.fill_se_opening(
                start,
                collector,
                random,
                weights,
                last_piece_type,
                1,
                1,
                pieces_to_process,
            );
        } else {
            self.piece.fill_nw_opening(
                start,
                collector,
                random,
                weights,
                last_piece_type,
                1,
                1,
                pieces_to_process,
            );
        }
    }

    fn place(
        &mut self,
        chunk: &mut ProtoChunk,
        _block_registry: &dyn WorldPortalExt,
        random: &mut RandomGenerator,
        _seed: i64,
        chunk_box: &BlockBox,
    ) {
        let randomizer = StoneBrickRandomizer;
        let box_limit = *chunk_box;
        let p = &self.piece;
        let inner = &p.piece;

        // 1. 5x5x5 Outline (Using randomizer)
        inner.fill_outline_random(
            0,
            0,
            0,
            4,
            4,
            4,
            &randomizer,
            chunk,
            true,
            random,
            &box_limit,
        );

        // 2. Entrance (Z=0)
        p.generate_entrance(chunk, &box_limit, self.piece.entry_door, 1, 1, 0);

        // 3. Exit logic based on Facing
        let air = Block::AIR.default_state;
        let facing = inner.facing.unwrap_or(BlockDirection::North);

        if facing == BlockDirection::North || facing == BlockDirection::East {
            // Exit on X=4 wall
            inner.fill_with_outline(chunk, &box_limit, false, 4, 1, 1, 4, 3, 3, air, air);
        } else {
            inner.fill_with_outline(chunk, &box_limit, false, 0, 1, 1, 0, 3, 3, air, air);
        }
    }
}
