use std::fmt::Debug;

use kyomu::{ReflectionRecursive, TyKindMapped};

pub trait ReflectionDebug {
    fn dbg(&self);
}

impl<T: ReflectionRecursive> ReflectionDebug for T {
    fn dbg(&self) {
        dbg_impl(&self.get_ty_recursive());
        println!("");
    }
}

fn dbg_impl(ty: &TyKindMapped) {
    match ty {
        TyKindMapped::DynTraitReference(mutable, preds) => {
            print!("&");
            if *mutable {
                print!("mut ");
            }
            if let Some(debug) = preds.try_as::<dyn Debug>() {
                print!("{debug:?}");
            } else {
                println!("dyn !Debug");
            }
        }
        TyKindMapped::IntMapped(int) => {
            print!("{int:?}");
        }
        TyKindMapped::FloatMapped(float) => {
            print!("{float:?}");
        }
        TyKindMapped::Tuple(tuple) => {
            print!("(");

            let mut first = true;
            for val in tuple {
                if !first {
                    print!(",");
                }
                first = false;
                dbg_impl(val);
            }

            print!(")");
        }
        TyKindMapped::Array(array) => {
            print!("[");

            let mut first = true;
            for val in array {
                if !first {
                    print!(",");
                }
                first = false;
                dbg_impl(val);
            }

            print!("]");
        }
        TyKindMapped::StrReference(mutable, str) => {
            print!("&");
            if *mutable {
                print!("mut ");
            }
            print!("\"{str}\"")
        }
        TyKindMapped::Reference(mutable, inner) => {
            print!("&");
            if *mutable {
                print!("mut ");
            }
            dbg_impl(inner);
        }
        TyKindMapped::SliceReference(mutable, types) => {
            print!("&");
            if *mutable {
                print!("mut ");
            }
            print!("[");

            let mut first = true;
            for val in types {
                if !first {
                    print!(",");
                }
                first = false;
                dbg_impl(val);
            }

            print!("]");
        }
    }
}

fn main() {
    1.dbg();
    1.1.dbg();

    ((1, 2, 3), (1, 2, (1, 2, 3.1))).dbg();

    (&&1).dbg();

    [1, 2, 3].dbg();

    (&&[1, 2]).dbg();

    (&[1u8, 2u8] as &[u8]).dbg();

    "test".dbg();

    (&"hi" as &(dyn Debug + Send)).dbg();
}

// alternative, does not require importing any Trait on call size
pub fn dbg(ty: &impl ReflectionRecursive) {
    dbg_impl(&ty.get_ty_recursive());
}
