use super::SwRenderer;
use super::blit_fast::{blit_1to1_fast, blit_2to2_fast, blit_dda};
use crate::draw::texture::Texture;
use crate::types::{Point, Rect};

impl SwRenderer<'_> {
    pub(super) fn blit_inner(
        &mut self,
        src: &Texture,
        src_rect: &Rect,
        dst: Point,
        dst_size: Point,
        clip: &Rect,
    ) {
        let phys_dst = self.viewport.point_to_physical(dst);
        let phys_dst_size = self.viewport.point_to_physical(dst_size);
        let phys_clip = self.viewport.rect_to_physical(*clip);
        let (sx0, sy0, sw, sh) = src_rect.to_px();
        // Negative clip x flowing through to the byte-offset math
        // (`dx0 as usize * 4`) wraps; clamp to target bounds first.
        let target_w = self.target.width as i32;
        let target_h = self.target.height as i32;
        let (raw_x0, raw_y0, raw_x1, raw_y1) = phys_clip.pixel_bounds();
        let clip_x0 = raw_x0.max(0);
        let clip_y0 = raw_y0.max(0);
        let clip_x1 = raw_x1.min(target_w);
        let clip_y1 = raw_y1.min(target_h);
        let dx0 = phys_dst.x.to_int();
        let dy0 = phys_dst.y.to_int();
        let dw = phys_dst_size.x.to_int();
        let dh = phys_dst_size.y.to_int();
        if dw <= 0 || dh <= 0 || sw == 0 || sh == 0 {
            return;
        }

        let sw_i = sw as i32;
        let sh_i = sh as i32;
        // 1× → format-specialized 1to1 fast path; 2× → 2to2; arbitrary → DDA.
        #[allow(clippy::if_same_then_else)]
        if dw == sw_i && dh == sh_i {
            blit_1to1_fast(
                &mut self.target,
                src,
                sx0,
                sy0,
                sw,
                sh,
                dx0,
                dy0,
                clip_x0,
                clip_y0,
                clip_x1,
                clip_y1,
            );
        } else if dw == sw_i * 2 && dh == sh_i * 2 {
            blit_2to2_fast(
                &mut self.target,
                src,
                sx0,
                sy0,
                sw,
                sh,
                dx0,
                dy0,
                clip_x0,
                clip_y0,
                clip_x1,
                clip_y1,
            );
        } else {
            blit_dda(
                &mut self.target,
                src,
                sx0,
                sy0,
                sw,
                sh,
                dx0,
                dy0,
                dw,
                dh,
                clip_x0,
                clip_y0,
                clip_x1,
                clip_y1,
            );
        }
    }
}
