import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:networks_sdk/src/annotations/api_request.dart';
import 'package:source_gen/source_gen.dart';
import 'package:build/build.dart';

/// @JsonKey 检测器（用于读取字段的 JSON 键名映射）
const _jsonKeyChecker = TypeChecker.fromUrl(
  'package:json_annotation/src/json_key.dart#JsonKey',
);

/// @ApiRequest 代码生成器
///
/// 为标注了 `@ApiRequest` 的类自动生成 mixin，提供：
/// - `path`, `method`, `requestType`, `includeToken` 协议实现
/// - `toJson()` — 从类的声明字段自动生成，只序列化自身字段，
///   不含 ApiRequestable 的继承属性，避免递归
/// - 自动注册响应类型的 `fromJson`（在 `parameters` getter 中触发）
///
/// 支持 `@JsonKey(name: '...')` 字段重命名。
/// 如有 `@JsonKey(includeToJson: false)` 则跳过该字段。
///
/// ## 使用模式（有响应数据）
///
/// ```dart
/// @ApiRequest(
///   path: ApiPaths.authLogin,
///   method: HttpMethod.post,
///   responseType: LoginResponse,
///   requestType: ApiRequestType.login,
/// )
/// class LoginRequest extends ApiRequestable<LoginResponse>
///     with _$LoginRequestApi {
///   final String email;
///   final String password;
///
///   LoginRequest({required this.email, required this.password});
///   // 完毕！toJson / path / method / fromJson 注册全部由 mixin 自动生成
/// }
/// ```
///
/// ## 使用模式（无响应数据）
///
/// ```dart
/// @ApiRequest(
///   path: ApiPaths.authLogout,
///   method: HttpMethod.post,
/// )
/// class LogoutRequest extends ApiRequestable<void>
///     with _$LogoutRequestApi {
///   LogoutRequest();
///   // responseType 省略 → mixin 跳过 fromJson 注册
/// }
/// ```
///
/// ## mixin 命名规则
///
/// `_$<ClassName>Api`
///
/// ## 生成示例（有响应数据）
///
/// ```dart
/// mixin _$LoginRequestApi on ApiRequestable<LoginResponse> {
///   @override String get path => '/auth/login';
///   @override HttpMethod get method => HttpMethod.post;
///   @override ApiRequestType get requestType => ApiRequestType.login;
///   @override bool get includeToken => false;
///   @override
///   Map<String, dynamic> toJson() => <String, dynamic>{
///     'email': (this as LoginRequest).email,
///     'password': (this as LoginRequest).password,
///   };
///   @override
///   Map<String, dynamic>? get parameters {
///     registerResponse<LoginResponse>(_$LoginResponseFromJson);
///     return super.parameters;
///   }
/// }
/// ```
///
/// ## Upload 等特殊请求
///
/// 如需自定义 toJson（如 upload 返回空 map），在类中 override 即可，
/// 类的 override 优先于 mixin。
class ApiRequestGenerator extends GeneratorForAnnotation<ApiRequest> {
  @override
  String generateForAnnotatedElement(
    Element element,
    ConstantReader annotation,
    BuildStep buildStep,
  ) {
    if (element is! ClassElement) {
      throw InvalidGenerationSourceError(
        '@ApiRequest can only be applied to classes.',
        element: element,
      );
    }

    final className = element.name!;

    // 尝试保留原始常量引用（如 ApiPaths.authSendOtp），
    // 这样修改 ApiPaths 里的值不需要重新跑 gen。
    // 若注解传的是字面量字符串，则回退为带引号字符串。
    final pathObject = annotation.read('path').objectValue;
    final pathVariable = pathObject.variable;
    final String pathExpression;
    if (pathVariable != null) {
      final enclosing = pathVariable.enclosingElement;
      if (enclosing is ClassElement) {
        pathExpression = '${enclosing.name}.${pathVariable.name!}';
      } else {
        pathExpression = pathVariable.name!;
      }
    } else {
      final pathValue = pathObject.toStringValue()!;
      pathExpression = "'$pathValue'";
    }

    // 读取 HttpMethod 枚举值
    final methodName = _readEnumName(
      annotation.read('method').objectValue,
      'post',
    );

    // 读取 responseType（可选：null 表示 void 响应，无需注册 fromJson）
    final responseTypePeek = annotation.peek('responseType');
    final bool hasResponseType =
        responseTypePeek != null && !responseTypePeek.isNull;
    final String responseTypeName = hasResponseType
        ? responseTypePeek.typeValue.getDisplayString()
        : 'void';

    // 读取 ApiRequestType 枚举值
    final requestTypeName = _readEnumName(
      annotation.read('requestType').objectValue,
      'request',
    );

    // 读取 includeToken（默认根据 requestType 推断：login → false，其余 → true）
    final includeTokenReader = annotation.peek('includeToken');
    final bool includeToken;
    if (includeTokenReader != null && !includeTokenReader.isNull) {
      includeToken = includeTokenReader.boolValue;
    } else {
      includeToken = requestTypeName != 'login';
    }

    // 从类的声明字段生成 toJson()
    final toJsonBody = _buildToJsonBody(element, className);

    // 有响应类型：parameters getter 中注册 fromJson（使用生成的私有函数）
    // ApiResponseGenerator 在同一 .g.dart 中生成 _$XFromJson，同 library 可访问
    // 无响应类型（void）：无需注册，不生成 parameters getter（避免 unnecessary_override）
    final parametersGetter = hasResponseType
        ? '''
  @override
  Map<String, dynamic>? get parameters {
    registerResponse<$responseTypeName>(_\$${responseTypeName}FromJson);
    return super.parameters;
  }'''
        : '';

    return '''
/// Generated by @ApiRequest for [$className]
mixin _\$${className}Api on ApiRequestable<$responseTypeName> {
  @override
  String get path => $pathExpression;
  @override
  HttpMethod get method => HttpMethod.$methodName;
  @override
  ApiRequestType get requestType => ApiRequestType.$requestTypeName;
  @override
  bool get includeToken => $includeToken;
  @override
  Map<String, dynamic> toJson() => $toJsonBody;$parametersGetter
}
''';
  }

  /// 从类的声明字段构建 toJson() 方法体
  ///
  /// 只读取类自身声明的实例字段（非 static、非 synthetic），
  /// 不含继承自 ApiRequestable 的属性，避免递归。
  /// 支持 @JsonKey(name: '...') 字段重命名，
  /// 以及 @JsonKey(includeToJson: false) 跳过字段。
  String _buildToJsonBody(ClassElement element, String className) {
    final fields = element.fields
        .where((f) => !f.isStatic && !f.isSynthetic)
        .toList();

    if (fields.isEmpty) {
      return '<String, dynamic>{}';
    }

    final entries = <String>[];
    for (final field in fields) {
      // 检查 @JsonKey 注解
      final jsonKeyAnnotation = _jsonKeyChecker.firstAnnotationOfExact(field);

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

      // JSON 键名：@JsonKey(name: '...') 或字段名
      final jsonName =
          jsonKeyAnnotation?.getField('name')?.toStringValue() ?? field.name;

      entries.add("'$jsonName': (this as $className).${field.name}");
    }

    if (entries.isEmpty) {
      return '<String, dynamic>{}';
    }

    return '<String, dynamic>{${entries.join(', ')}}';
  }

  /// 从 DartObject 提取枚举常量名称
  String _readEnumName(dynamic dartObject, String defaultValue) {
    final index = dartObject.getField('index')?.toIntValue();
    if (index == null) return defaultValue;

    final type = dartObject.type;
    if (type is InterfaceType) {
      final constants = type.element.fields
          .where((f) => f.isEnumConstant)
          .toList();
      if (index < constants.length) {
        return constants[index].name ?? defaultValue;
      }
    }

    return defaultValue;
  }
}
