package com.example.scaffold.learning;

import com.example.scaffold.learning.reflection.ReflectionLabTarget;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/api/learning/reflection")
public class ReflectionLearningController {

    @GetMapping("/overview")
    public Map<String, Object> overview() {
        return Map.of(
                "whatIsReflection", List.of(
                        "运行时检查类、字段、方法、构造器",
                        "运行时动态创建对象",
                        "运行时调用方法、读写字段",
                        "Spring / MyBatis / Jackson 等框架大量依赖反射"
                ),
                "whyItMatters", List.of(
                        "理解框架为什么能自动装配、自动绑定、自动序列化",
                        "理解代理、注解扫描、Bean 创建背后的机制",
                        "理解反射带来的灵活性与性能成本"
                )
        );
    }

    @GetMapping("/class-info")
    public Map<String, Object> classInfo() throws Exception {
        Class<?> clazz = ReflectionLabTarget.class;
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("className", clazz.getName());
        result.put("simpleName", clazz.getSimpleName());
        result.put("constructors", Arrays.stream(clazz.getDeclaredConstructors()).map(Constructor::toString).toList());
        result.put("fields", Arrays.stream(clazz.getDeclaredFields()).map(Field::toString).toList());
        result.put("methods", Arrays.stream(clazz.getDeclaredMethods()).map(Method::toString).toList());
        return result;
    }

    @GetMapping("/instantiate")
    public Map<String, Object> instantiate(@RequestParam(defaultValue = "ref-user") String name,
                                           @RequestParam(defaultValue = "5") int count) throws Exception {
        Constructor<ReflectionLabTarget> constructor = ReflectionLabTarget.class.getDeclaredConstructor(String.class, int.class);
        ReflectionLabTarget obj = constructor.newInstance(name, count);
        return Map.of(
                "instance", obj.getClass().getName(),
                "identityHashCode", System.identityHashCode(obj),
                "name", obj.getName(),
                "count", obj.getCount(),
                "message", "通过反射构造器动态创建对象成功"
        );
    }

    @GetMapping("/field-access")
    public Map<String, Object> fieldAccess(@RequestParam(defaultValue = "changed-by-reflection") String value) throws Exception {
        ReflectionLabTarget obj = new ReflectionLabTarget();
        Field field = ReflectionLabTarget.class.getDeclaredField("name");
        field.setAccessible(true);
        Object before = field.get(obj);
        field.set(obj, value);
        Object after = field.get(obj);
        return Map.of(
                "field", field.getName(),
                "before", before,
                "after", after,
                "message", "私有字段已通过反射修改"
        );
    }

    @GetMapping("/method-call")
    public Map<String, Object> methodCall(@RequestParam(defaultValue = "你好") String prefix) throws Exception {
        ReflectionLabTarget obj = new ReflectionLabTarget("Spring", 2);
        Method publicMethod = ReflectionLabTarget.class.getDeclaredMethod("greet", String.class);
        Object publicResult = publicMethod.invoke(obj, prefix);

        Method privateMethod = ReflectionLabTarget.class.getDeclaredMethod("secretFormula", String.class);
        privateMethod.setAccessible(true);
        Object privateResult = privateMethod.invoke(obj, "debug");

        Method staticMethod = ReflectionLabTarget.class.getDeclaredMethod("staticInfo");
        Object staticResult = staticMethod.invoke(null);

        return Map.of(
                "publicMethodResult", publicResult,
                "privateMethodResult", privateResult,
                "staticMethodResult", staticResult,
                "message", "公开方法、私有方法、静态方法都已通过反射调用"
        );
    }

    @GetMapping("/why-frameworks-use-it")
    public Map<String, Object> whyFrameworksUseIt() {
        return Map.of(
                "spring", List.of("扫描注解", "创建 Bean", "依赖注入", "调用生命周期方法"),
                "jackson", List.of("读取字段", "调用 getter/setter", "对象序列化/反序列化"),
                "mybatis", List.of("结果集映射到对象", "动态代理 Mapper 接口"),
                "warning", "反射很强大，但要理解它的性能成本、可读性成本和封装破坏风险"
        );
    }
}
