import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:source_gen/source_gen.dart';
import 'package:build/build.dart';

/// @JsonKey 检测器（与 ApiRequestGenerator 共用相同策略）
const _jsonKeyChecker = TypeChecker.fromUrl(
  'package:json_annotation/src/json_key.dart#JsonKey',
);

/// @ApiRequest 检测器（复用，用于找到所有 responseType 入口）
const _apiRequestChecker = TypeChecker.fromUrl(
  'package:networks_sdk/src/annotations/api_request.dart#ApiRequest',
);

/// Response 反序列化代码生成器
///
/// 从同一 library 中的 `@ApiRequest(responseType: T)` 声明出发，
/// 自动生成 `_$TFromJson` 私有函数，无需在 Response 类上添加任何注解。
///
/// ## 设计原理
///
/// App 层只需标注 Request 类：
/// ```dart
/// @ApiRequest(path: '...', responseType: LoginResponse)
/// class LoginRequest extends ApiRequestable<LoginResponse>
///     with _$LoginRequestApi { ... }
/// ```
///
/// 生成器从 `responseType` 出发，递归找到所有嵌套自定义类型，
/// 在同一 `.g.dart` 中生成所有 `_$XFromJson` 私有函数。
///
/// Response 类体本身是纯 Dart 类，**无需任何注解，无需 factory fromJson**：
/// ```dart
/// class LoginResponse {
///   @JsonKey(name: 'access_token')
///   final String accessToken;
///   final LoginProfile profile;
///   // 完毕！fromJson 由生成器自动提供
/// }
/// ```
///
/// ## 生成示例
///
/// ```dart
/// LoginProfile _$LoginProfileFromJson(Map<String, dynamic> json) {
///   return LoginProfile(
///     uid: json['uid'] as int,
///     uuid: json['uuid'] as String,
///   );
/// }
///
/// LoginResponse _$LoginResponseFromJson(Map<String, dynamic> json) {
///   return LoginResponse(
///     accessToken: json['access_token'] as String,
///     profile: _$LoginProfileFromJson(json['profile'] as Map<String, dynamic>),
///   );
/// }
/// ```
///
/// ## 支持的字段类型
///
/// - 基础类型（String / int / bool / double / num）
/// - 可空类型（String? / int? / 自定义类?）
/// - 嵌套对象（自动递归，在同一 `.g.dart` 中生成被依赖类的函数）
/// - `@JsonKey(name: '...')` 字段重命名
/// - `@JsonKey(includeFromJson: false)` 跳过字段
class ApiResponseGenerator extends Generator {
  @override
  String generate(LibraryReader library, BuildStep buildStep) {
    final buffer = StringBuffer();
    // 跟踪已生成的类，避免同一 library 中多个 Request 引用同一 Response 类时重复生成
    final generated = <String>{};

    for (final annotated in library.annotatedWith(_apiRequestChecker)) {
      final annotation = annotated.annotation;
      final responseTypePeek = annotation.peek('responseType');
      if (responseTypePeek == null || responseTypePeek.isNull) continue;

      final responseType = responseTypePeek.typeValue;
      if (responseType is! InterfaceType) continue;

      final responseClass = responseType.element;
      if (responseClass is! ClassElement) continue;

      // 只生成属于当前 library 的类（跨包类型跳过）
      if (responseClass.library != library.element) continue;

      _generateRecursive(responseClass, library, generated, buffer);
    }

    return buffer.toString();
  }

  /// 递归生成：先生成被依赖的嵌套类型，再生成当前类型（保证引用顺序）
  void _generateRecursive(
    ClassElement element,
    LibraryReader library,
    Set<String> generated,
    StringBuffer buffer,
  ) {
    final typeName = element.name!;
    if (generated.contains(typeName)) return;
    generated.add(typeName);

    // 先递归处理嵌套的自定义类型
    // InterfaceType 的 element 在 nullable 和非 nullable 情况下指向同一个 ClassElement
    for (final field in element.fields.where(
      (f) => !f.isStatic && !f.isSynthetic,
    )) {
      final fieldType = field.type;
      if (fieldType is InterfaceType) {
        final fieldClass = fieldType.element;
        if (fieldClass is ClassElement &&
            fieldClass.library == library.element &&
            !_isPrimitive(fieldClass.name!)) {
          _generateRecursive(fieldClass, library, generated, buffer);
        }
      }
    }

    final params = _buildConstructorParams(element);
    buffer.write('''
/// Generated by ApiResponseGenerator for [$typeName]
$typeName _\$${typeName}FromJson(Map<String, dynamic> json) {
  return $typeName(
$params  );
}
''');
  }

  /// 判断是否为不需要递归生成的基础类型
  bool _isPrimitive(String typeName) {
    const primitives = {
      'String',
      'int',
      'double',
      'bool',
      'num',
      'dynamic',
      'Object',
      'List',
      'Map',
      'Set',
      'Iterable',
    };
    return primitives.contains(typeName);
  }

  /// 从类的字段生成构造函数参数列表
  String _buildConstructorParams(ClassElement element) {
    final fields = element.fields
        .where((f) => !f.isStatic && !f.isSynthetic)
        .toList();

    final lines = <String>[];
    for (final field in fields) {
      final jsonKeyAnnotation = _jsonKeyChecker.firstAnnotationOfExact(field);

      // @JsonKey(includeFromJson: false) → 跳过
      final includeFromJson = jsonKeyAnnotation
          ?.getField('includeFromJson')
          ?.toBoolValue();
      if (includeFromJson == false) continue;

      final fieldName = field.name!;
      final jsonName =
          jsonKeyAnnotation?.getField('name')?.toStringValue() ?? fieldName;

      final type = field.type;
      final isNullable = type.nullabilitySuffix == NullabilitySuffix.question;
      final expr = _castExpression(type, jsonName, isNullable);

      lines.add('    $fieldName: $expr,');
    }

    return lines.join('\n');
  }

  /// 根据字段类型生成 JSON 取值表达式
  String _castExpression(DartType type, String jsonKey, bool isNullable) {
    final q = isNullable ? '?' : '';
    final access = "json['$jsonKey']";

    // 基础类型：直接 as 转换
    if (type.isDartCoreString) return '$access as String$q';
    if (type.isDartCoreInt) return '$access as int$q';
    if (type.isDartCoreBool) return '$access as bool$q';
    if (type.isDartCoreDouble) return '$access as double$q';
    if (type.isDartCoreNum) return '$access as num$q';

    // Map<String, dynamic>：已经是 JSON Map，直接 cast，无需 fromJson
    if (type.isDartCoreMap) return '$access as Map<String, dynamic>$q';

    // 嵌套对象：调用同一 part 文件中生成的 _$TypeFromJson 私有函数
    if (type is InterfaceType) {
      final typeName = type.element.name!;
      if (isNullable) {
        return '$access == null ? null : _\$${typeName}FromJson($access as Map<String, dynamic>)';
      }
      return '_\$${typeName}FromJson($access as Map<String, dynamic>)';
    }

    // 兜底
    return '$access as dynamic';
  }
}
