import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:build/build.dart';
import 'package:built_collection/built_collection.dart';
import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';
import 'package:design_generator/src/tuple.dart';
import 'package:design_spec/design_spec.dart' as _design;
import 'package:design_spec/design_spec.dart';
import 'package:source_gen/source_gen.dart';

import 'dart:ffi';
import 'dart:io';

import 'package:analyzer/dart/constant/value.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:build/build.dart';
import 'package:built_collection/built_collection.dart';
import 'package:code_builder/code_builder.dart';
import 'package:dart_style/dart_style.dart';
import 'package:source_gen/source_gen.dart';

/// Created by Haoyi on 2022/5/26

Builder generatorFactoryBuilder(BuilderOptions options) =>
    SharedPartBuilder([DesignSpecGenerator()], "design_spec");

class FieldProcessor {
  final dynamic _annotationType;
  final List<String> _validTypeNames;
  final Code Function(FieldElement element, ConstantReader annotation) assigner;

  FieldProcessor(this._annotationType, this._validTypeNames, this.assigner);
}

class DesignSpecGenerator extends GeneratorForAnnotation<_design.DesignSpec> {
  static const widthField = "width";
  static const heightField = "height";
  static const specModeField = "specMode";
  @deprecated
  static const nestedSpecField = "nestedSpec";
  static const textScaleFactorField = "textScaleFactor";

  final _fieldAnnotationProcessors = [
    FieldProcessor(_design.SpecOrigin, ["double"], _generateAssignSpecOrigin),
    FieldProcessor(_design.SpecHeight, ["double"], _generateAssignSpecHeight),
    FieldProcessor(_design.SpecWidth, ["double"], _generateAssignSpecWidth),
    FieldProcessor(_design.SpecVertical, ["double"], _generateAssignSpecVertical),
    FieldProcessor(_design.SpecHorizontal, ["double"], _generateAssignSpecHorizontal),
    FieldProcessor(_design.SpecFontSize, ["double"], _generateAssignSpecFontSize),
    FieldProcessor(_design.SpecAbsoluteFontSize, ["double"], _generateAssignSpecAbsoluteFontSize),
    FieldProcessor(_design.SpecStatusBarHeight, ["double"], _generateAssignSpecStatusBarHeight),
    FieldProcessor(
        _design.SpecNavigationBarHeight, ["double"], _generateAssignSpecNavigationBarHeight),
    FieldProcessor(_design.CombinedSpec, ["double"], _generateAssignCombinedSpec),
    FieldProcessor(_design.SpecSize, ["Size"], _generateAssignSpecSize),
    FieldProcessor(_design.SpecAspectHeightSize, ["Size"], _generateAssignSpecAspectHeightSize),
    FieldProcessor(_design.SpecAspectWidthSize, ["Size"], _generateAssignSpecAspectWidthSize),
    FieldProcessor(_design.SpecOffset, ["Offset"], _generateAssignSpecOffset),
    FieldProcessor(_design.SpecRect, ["Rect", "RelativeRect"], _generateAssignSpecRect),
    FieldProcessor(_design.SpecRRect, ["RRect"], _generateAssignSpecRRect),
    FieldProcessor(_design.SpecList, ["List<double>"], _generateAssignSpecList),
    FieldProcessor(_design.NestedSpec, [], _generateAssignNestedSpec),
    FieldProcessor(_design.NestedAspectSpec, [], _generateAssignNestedAspectSpec),
    FieldProcessor(_design.NestedAspectHeightSpec, [], _generateAssignNestedAspectHeightSpec),
    FieldProcessor(_design.NestedAspectWidthSpec, [], _generateAssignNestedAspectWidthSpec),
    FieldProcessor(
        _design.SpecRadius,
        ["BorderRadiusGeometry", "BorderRadius", "BorderRadiusDirectional", "Radius"],
        _generateAssignSpecRadius),
    FieldProcessor(
        _design.SpecEdgeInsets,
        ["EdgeInsets", "EdgeInsetsGeometry", "EdgeInsetsDirectional"],
        _generateAssignSpecEdgeInsets),
  ];

  late _design.DesignSpec designSpec;

  @override
  generateForAnnotatedElement(Element element, ConstantReader annotation, BuildStep buildStep) {
    if (element is! ClassElement) {
      final name = element.displayName;
      final todo = 'Remove the [DesignSpec] annotation from `$name`.';
      throw InvalidGenerationSourceError(
        'Generator cannot target `$name`.\n[TODO] $todo',
        todo: 'Remove the [DesignSpec] annotation from `$name`.',
      );
    }
    if (!element.isAbstract) {
      final name = element.displayName;
      final todo = 'Please change class [$name] to `abstract` class.';
      throw InvalidGenerationSourceError(
        'Generator cannot target `$name`.\n[TODO] $todo',
        todo: todo,
      );
    }
    bool isBasicDesignSpec = false;
    for (var type in element.allSupertypes) {
      if (type.getDisplayString(withNullability: false) == "BasicDesignSpec") {
        isBasicDesignSpec = true;
        break;
      }
    }
    if (!isBasicDesignSpec) {
      final name = element.displayName;
      const todo = 'Please inherit the `BasicDesignSpec` class.';
      throw InvalidGenerationSourceError(
        'Generator cannot target `$name`.\n[TODO] $todo',
        todo: todo,
      );
    }
    final nestedSpec = annotation.peek(nestedSpecField)?.boolValue == true;
    final specMode = nestedSpec
        ? SpecMode.nested
        : (annotation.peek(specModeField)?.intValue ?? SpecMode.useGet);
    final textScaleFactor = annotation.peek(textScaleFactorField)?.doubleValue;
    designSpec = _design.DesignSpec(
        width: annotation.peek(widthField)?.doubleValue ?? 0.0,
        height: annotation.peek(heightField)?.doubleValue ?? 0.0,
        specMode: specMode,
        nestedSpec: nestedSpec,
        textScaleFactor: textScaleFactor);
    if (designSpec.specMode == SpecMode.nested && element.getMethod("create")?.isStatic != true) {
      final name = element.displayName;
      const todo = 'Nested specs need to provide a static `create` function';
      throw InvalidGenerationSourceError(
        'Generator cannot target `$name`.\n[TODO] $todo',
        todo: todo,
      );
    }
    return _implementClass(element, annotation);
  }

  String _implementClass(ClassElement element, ConstantReader annotation) {
    log.info("_implementClass methods:${element.fields.map((e) => e.name)}");
    final className = element.name;
    final tuple2 = _generateDesignFields(element);
    final fields = tuple2.item1;
    final blocks = tuple2.item2;
    final classBuilder = Class((clazz) {
      clazz
        ..name = '_$className'
        ..fields.addAll([
          _buildDesignMetrics(),
          _buildCurrentDesignSpec(element),
          ...fields,
          _buildMeasuredMetrics(),
          _buildSpecOffset()
        ])
        ..constructors.add(buildConstructor(fields))
        ..methods.addAll([_buildMeasuredSizeGetter(), _buildCreator(element, blocks)])
        ..methods.addAll(designSpec.nestedSpec ? [] : [_buildGetter(element)])
        ..extend = refer(className);
    });
    final emitter = DartEmitter();
    return DartFormatter().format([classBuilder.accept(emitter)].join('\n\n'));
  }

  String _specFunction() {
    switch (designSpec.specMode) {
      case _design.SpecMode.useContext:
        return "of";
      case _design.SpecMode.useSize:
      case _design.SpecMode.nested:
        return "from";
      default:
        return "get";
    }
  }

  List<Parameter> _specParameters() {
    switch (designSpec.specMode) {
      case _design.SpecMode.useContext:
        return [
          Parameter((p) => p
            ..type = refer("BuildContext")
            ..name = "context")
        ];
      case _design.SpecMode.useSize:
      case _design.SpecMode.nested:
        return [
          Parameter((p) => p
            ..type = refer("Size")
            ..name = "size")
        ];
      default:
        return [];
    }
  }

  Method _buildGetter(ClassElement element) => Method((m) => m
    ..name = _specFunction()
    ..static = true
    ..requiredParameters.addAll(_specParameters())
    ..optionalParameters.addAll([
      Parameter((p) => p
        ..name = "offset"
        ..named = true
        ..defaultTo = const Code('Offset.zero')
        ..type = refer("Offset"))
    ])
    ..body = _buildGetterCode(element)
    ..returns = refer(element.name));

  Code _buildGetterCode(ClassElement element) {
    final blocks = <Code>[];
    switch (designSpec.specMode) {
      case _design.SpecMode.useContext:
        blocks.add(refer("final Size measuredSize = MediaQuery.of(context).size").statement);
        break;
      case _design.SpecMode.useSize:
      case _design.SpecMode.nested:
        blocks.add(refer("final Size measuredSize = size").statement);
        break;
      default:
        blocks.add(refer("final Size measuredSize = Get.size").statement);
        break;
    }

    blocks.add(refer("final key = BasicDesignSpec.buildSpecKey(measuredSize, offset)").statement);
    blocks.add(refer("_${element.name}? designSpec = _cache[key]").statement);
    blocks.add(const Code("if (kDebugMode || designSpec == null) {"));
    blocks.add(refer("designSpec = _create(measuredSize, offset: offset)").statement);
    blocks.add(refer("_cache[key] = designSpec").statement);
    blocks.add(const Code("}"));
    blocks.add(refer("return designSpec").statement);

    return Block.of(blocks);
  }

  Method _buildCreator(ClassElement element, List<Code> blocks) => Method((m) => m
    ..name = "_create"
    ..static = true
    ..body = _buildCreatorCode(element, blocks)
    ..requiredParameters.addAll([
      Parameter((p) => p
        ..name = "measuredSize"
        ..type = refer("Size")),
    ])
    ..optionalParameters.addAll([
      Parameter((p) => p
        ..name = "offset"
        ..named = true
        ..defaultTo = const Code('Offset.zero')
        ..type = refer("Offset"))
    ])
    ..returns = refer("_${element.name}"));

  Code _buildCreatorCode(ClassElement element, List<Code> blocks) {
    final createBlocks = <Code>[];
    createBlocks
        .add(refer("final _measuredMetrics = designMetrics.measure(measuredSize)").statement);
    createBlocks.add(Code("return _${element.name}._("));
    createBlocks.add(const Code("_measuredMetrics, offset, "));
    createBlocks.addAll(blocks);
    createBlocks.add(const Code(");"));
    return Block.of(createBlocks);
  }

  Constructor buildConstructor(List<Field> fields) => Constructor((c) => c
    ..name = "_"
    ..requiredParameters.addAll([
      Parameter((p) => p
        ..name = "measuredMetrics"
        ..toThis = true),
      Parameter((p) => p
        ..name = "specOffset"
        ..toThis = true)
    ])
    ..requiredParameters.addAll(fields
        .map((field) => Parameter((p) => p
          ..name = field.name
          ..toThis = true))
        .toList()));

  Field _buildDesignMetrics() => Field((field) => field
    ..name = "designMetrics"
    ..static = true
    ..assignment = designSpec.textScaleFactor == null
        ? Code("DesignMetrics.create(const Size(${designSpec.width}, ${designSpec.height}))")
        : Code(
            "DesignMetrics.create(const Size(${designSpec.width}, ${designSpec.height}), adaptation: const SystemAdaptation(textScaleFactor: ${designSpec.textScaleFactor}))")
    ..modifier = FieldModifier.final$);

  Field _buildCurrentDesignSpec(ClassElement element) => Field((field) => field
    ..name = "_cache"
    ..static = true
    ..assignment = const Code("{}")
    ..type = refer("Map<String, _${element.name}>")
    ..modifier = FieldModifier.final$);

  Field _buildMeasuredSize() => Field((field) => field
    ..name = "measuredSize"
    ..type = refer("Size")
    ..annotations.add(const CodeExpression(Code('override')))
    ..modifier = FieldModifier.final$);

  Field _buildMeasuredMetrics() => Field((field) => field
    ..name = "measuredMetrics"
    ..type = refer("MeasuredMetrics")
    ..annotations.add(const CodeExpression(Code('override')))
    ..modifier = FieldModifier.final$);

  Field _buildSpecOffset() => Field((field) => field
    ..name = "specOffset"
    ..type = refer("Offset")
    ..annotations.add(const CodeExpression(Code('override')))
    ..modifier = FieldModifier.final$);

  Method _buildMetricGetter() => Method((m) => m
    ..name = "metrics"
    ..type = MethodType.getter
    ..returns = refer("DesignMetrics")
    ..annotations.add(const CodeExpression(Code('override')))
    ..lambda = true
    ..body = const Code("_metrics"));

  Method _buildMeasuredSizeGetter() => Method((m) => m
    ..name = "measuredSize"
    ..type = MethodType.getter
    ..returns = refer("Size")
    ..annotations.add(const CodeExpression(Code('override')))
    ..lambda = true
    ..body = const Code("measuredMetrics.size"));

  static TypeChecker _typeChecker(Type type) => TypeChecker.fromRuntime(type);

  Tuple2<List<Field>, List<Code>> _generateDesignFields(ClassElement classElement) {
    final fields = <Field>[];
    final blocks = <Code>[];
    for (var fieldElement in classElement.fields) {
      // log.info("fieldName:${fieldElement.name} ${fieldElement.metadata}");
      final getterElement = classElement.getGetter(fieldElement.name);
      if (getterElement != null) {
        for (final processor in _fieldAnnotationProcessors) {
          final annotation = _typeChecker(processor._annotationType)
              .firstAnnotationOf(getterElement, throwOnUnresolved: false);
          // log.info("generator:${processor._annotationType} annotation:${annotation?.type?.name}");
          if (annotation != null) {
            final field = _generateDefinedDesignField(fieldElement, processor._validTypeNames);
            fields.add(field);
            blocks.add(processor.assigner.call(fieldElement, ConstantReader(annotation)));
            break;
          }
        }
      }
    }
    return Tuple2(fields, blocks);
  }

  static void ensuredUseValidElementType(FieldElement fieldElement, List<String> typeNames) {
    if (typeNames.isNotEmpty &&
        !typeNames.contains(fieldElement.type.getDisplayString(withNullability: false))) {
      final name = fieldElement.displayName;
      log.shout(
          "Generator cannot target Field `$name`.\n[TODO] Please change field [$name] to `double` Type.");
      throw InvalidGenerationSourceError(
        'Generator cannot target Field `$name`.',
        todo: 'Please change field [$name] to `$typeNames` Type.',
      );
    }
  }

  static Field _generateDefinedDesignField(FieldElement fieldElement, List<String> typeNames) {
    ensuredUseValidElementType(fieldElement, typeNames);
    return Field((field) => field
      ..name = fieldElement.name
      ..type = refer(fieldElement.type.getDisplayString(withNullability: false))
      ..annotations.add(const CodeExpression(Code('override')))
      ..modifier = FieldModifier.final$);
  }

  static Code _generateAssignSpecOrigin(FieldElement fieldElement, ConstantReader annotation) {
    return Code("${annotation.peek('value')?.doubleValue}, // ${fieldElement.name}");
  }

  static Code _generateAssignSpecHeight(FieldElement fieldElement, ConstantReader annotation) {
    return Code(
        "_measuredMetrics.measureHeight(${annotation.peek('height')?.doubleValue}, consistent: ${annotation.peek('consistent')?.boolValue ?? false}), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecWidth(FieldElement fieldElement, ConstantReader annotation) {
    return Code(
        "_measuredMetrics.measureWidth(${annotation.peek('width')?.doubleValue}), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecHorizontal(FieldElement fieldElement, ConstantReader annotation) {
    final isRelative = annotation.peek('relative')?.boolValue == true;
    return Code(
        "_measuredMetrics.measureHorizontal(${annotation.peek('horizontal')?.doubleValue})${isRelative ? " + offset.dx" : ""}, // ${fieldElement.name}");
  }

  static Code _generateAssignSpecVertical(FieldElement fieldElement, ConstantReader annotation) {
    final isRelative = annotation.peek('relative')?.boolValue == true;
    return Code(
        "_measuredMetrics.measureVertical(${annotation.peek('vertical')?.doubleValue})${isRelative ? " + offset.dy" : ""}, // ${fieldElement.name}");
  }

  static Code _generateAssignSpecFontSize(FieldElement fieldElement, ConstantReader annotation) {
    return Code(
        "_measuredMetrics.measureFontSize(${annotation.peek('fontSize')?.doubleValue}), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecAbsoluteFontSize(
      FieldElement fieldElement, ConstantReader annotation) {
    return Code(
        "_measuredMetrics.measureAbsoluteFontSize(${annotation.peek('fontSize')?.doubleValue}, consistent: ${annotation.peek('consistent')?.boolValue ?? false}), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecStatusBarHeight(
      FieldElement fieldElement, ConstantReader annotation) {
    if (annotation.peek('wrappedInSafeArea')?.boolValue != true) {
      return Code(
          "_measuredMetrics.statusBarHeight(${annotation.peek('ifAbsent')?.doubleValue}), // ${fieldElement.name}");
    } else {
      return Code(
          "_measuredMetrics.wrappedInSafeAreaStatusBarHeight(${annotation.peek('ifAbsent')?.doubleValue}), // ${fieldElement.name}");
    }
  }

  static Code _generateAssignSpecNavigationBarHeight(
      FieldElement fieldElement, ConstantReader annotation) {
    if (annotation.peek('wrappedInSafeArea')?.boolValue != true) {
      return Code(
          "_measuredMetrics.navigationBarHeight(${annotation.peek('ifAbsent')?.doubleValue}), // ${fieldElement.name}");
    } else {
      return Code(
          "_measuredMetrics.wrappedInSafeAreaNavigationBarHeight(${annotation.peek('ifAbsent')?.doubleValue}), // ${fieldElement.name}");
    }
  }

  static Code _generateAssignCombinedSpec(FieldElement fieldElement, ConstantReader annotation) {
    final spec1 = generateMeasureCodeFromDesignSpecField(annotation.peek('spec1')?.objectValue);
    final spec2 = generateMeasureCodeFromDesignSpecField(annotation.peek('spec2')?.objectValue);
    return Code("($spec1 + $spec2), // ${fieldElement.name}");
  }

  static String generateMeasureCodeFromDesignSpecField(DartObject? dartObject,
      {double defValue = 0}) {
    if (dartObject == null) {
      throw InvalidGenerationSourceError(
        'Not Found Valid Arg `${dartObject.runtimeType}`.',
        todo: 'Please change field Type.',
      );
    }
    if (dartObject.type?.getDisplayString(withNullability: false) == "SpecVertical") {
      final value = dartObject.getField("vertical")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureVertical($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecHorizontal") {
      final value = dartObject.getField("horizontal")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureHorizontal($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecHeight") {
      final value = dartObject.getField("height")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureHeight($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecWidth") {
      final value = dartObject.getField("width")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureWidth($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecOrigin") {
      final value = dartObject.getField("value")?.toDoubleValue() ?? defValue;
      return "$value";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecStatusBarHeight") {
      final ifAbsent = dartObject.getField("ifAbsent")?.toDoubleValue() ?? defValue;
      if (dartObject.getField('wrappedInSafeArea')?.toBoolValue() != true) {
        return "_measuredMetrics.statusBarHeight($ifAbsent)";
      } else {
        return "_measuredMetrics.wrappedInSafeAreaStatusBarHeight($ifAbsent)";
      }
    } else if (dartObject.type?.getDisplayString(withNullability: false) ==
        "SpecNavigationBarHeight") {
      final ifAbsent = dartObject.getField("ifAbsent")?.toDoubleValue() ?? defValue;
      if (dartObject.getField('wrappedInSafeArea')?.toBoolValue() != true) {
        return "_measuredMetrics.navigationBarHeight($ifAbsent)";
      } else {
        return "_measuredMetrics.wrappedInSafeAreaNavigationBarHeight($ifAbsent)";
      }
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "CombinedSpec") {
      final spec1 = generateMeasureCodeFromDesignSpecField(dartObject.getField("spec1"));
      final spec2 = generateMeasureCodeFromDesignSpecField(dartObject.getField("spec2"));
      return "($spec1 + $spec2)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecFontSize") {
      final value = dartObject.getField("fontSize")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureFontSize($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) ==
        "SpecAbsoluteFontSize") {
      final value = dartObject.getField("fontSize")?.toDoubleValue() ?? defValue;
      return "_measuredMetrics.measureAbsoluteFontSize($value)";
    } else if (dartObject.type?.getDisplayString(withNullability: false) == "SpecRadius") {
      final topStart = generateMeasureCodeFromDesignSpecField(dartObject.getField("topStart"));
      // final topEnd = generateMeasureCodeFromDesignSpecField(dartObject.getField("topEnd"));
      // final bottomStart = generateMeasureCodeFromDesignSpecField(dartObject.getField("bottomStart"));
      // final bottomEnd = generateMeasureCodeFromDesignSpecField(dartObject.getField("bottomEnd"));
      return "Radius.circular($topStart)";
    } else {
      throw InvalidGenerationSourceError(
        'Not Found Valid Arg `${dartObject.runtimeType}`.',
        todo: 'Please change field Type.',
      );
    }
  }

  static Code _generateAssignSpecEdgeInsets(FieldElement fieldElement, ConstantReader annotation) {
    final start = generateMeasureCodeFromDesignSpecField(annotation.peek('start')?.objectValue);
    final end = generateMeasureCodeFromDesignSpecField(annotation.peek('end')?.objectValue);
    final top = generateMeasureCodeFromDesignSpecField(annotation.peek('top')?.objectValue);
    final bottom = generateMeasureCodeFromDesignSpecField(annotation.peek('bottom')?.objectValue);
    if (fieldElement.type.getDisplayString(withNullability: false) == 'EdgeInsets') {
      return Code("EdgeInsets.only(left:$start, right:$end, top:$top, bottom:$bottom),");
    } else {
      return Code(
          "EdgeInsetsDirectional.only(start:$start, end:$end, top:$top, bottom:$bottom), // ${fieldElement.name}");
    }
  }

  static Code _generateAssignSpecRadius(FieldElement fieldElement, ConstantReader annotation) {
    String toRadiusCode(String code) {
      return "Radius.circular($code)";
    }

    final topStart =
        generateMeasureCodeFromDesignSpecField(annotation.peek('topStart')?.objectValue);
    final topEnd = generateMeasureCodeFromDesignSpecField(annotation.peek('topEnd')?.objectValue);
    final bottomStart =
        generateMeasureCodeFromDesignSpecField(annotation.peek('bottomStart')?.objectValue);
    final bottomEnd =
        generateMeasureCodeFromDesignSpecField(annotation.peek('bottomEnd')?.objectValue);

    final sameCode = topStart == topEnd && topEnd == bottomStart && bottomStart == bottomEnd;
    final fieldTypeName = fieldElement.type.getDisplayString(withNullability: false);
    if (sameCode && fieldTypeName == 'Radius') {
      return Code("Radius.circular($topStart),");
    } else if (fieldTypeName == 'BorderRadius') {
      if (sameCode) {
        return Code("BorderRadius.circular($topStart),");
      } else {
        return Code(
            "BorderRadius.only(topLeft:${toRadiusCode(topEnd)}, topRight:${toRadiusCode(topEnd)}, bottomLeft:${toRadiusCode(bottomStart)}, bottomRight:${toRadiusCode(bottomEnd)}),");
      }
    } else {
      if (sameCode) {
        return Code("BorderRadiusDirectional.circular($topStart), // ${fieldElement.name}");
      } else {
        return Code(
            "BorderRadiusDirectional.only(topStart:${toRadiusCode(topStart)}, topEnd:${toRadiusCode(topEnd)}, bottomStart:${toRadiusCode(bottomStart)}, bottomEnd:${toRadiusCode(bottomEnd)}), // ${fieldElement.name}");
      }
    }
  }

  static Code _generateAssignSpecSize(FieldElement fieldElement, ConstantReader annotation) {
    final width = generateMeasureCodeFromDesignSpecField(annotation.peek('width')?.objectValue);
    final height = generateMeasureCodeFromDesignSpecField(annotation.peek('height')?.objectValue);
    return Code("Size($width, $height), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecAspectHeightSize(
      FieldElement fieldElement, ConstantReader annotation) {
    final value = annotation.peek('height')?.doubleValue;
    final height = "_measuredMetrics.measureHeight($value)";
    final ratio = annotation.peek('aspectRatio')?.doubleValue;
    return Code("Size($height * $ratio, $height), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecAspectWidthSize(
      FieldElement fieldElement, ConstantReader annotation) {
    final value = annotation.peek('width')?.doubleValue;
    final width = "_measuredMetrics.measureWidth($value)";
    final ratio = annotation.peek('aspectRatio')?.doubleValue;
    return Code("Size($width, $width * $ratio), // ${fieldElement.name}");
  }

  static Code _generateAssignSpecOffset(FieldElement fieldElement, ConstantReader annotation) {
    final isRelative = annotation.peek('relative')?.boolValue == true;
    final dx = generateMeasureCodeFromDesignSpecField(annotation.peek('dx')?.objectValue);
    final dy = generateMeasureCodeFromDesignSpecField(annotation.peek('dy')?.objectValue);
    return Code("Offset($dx, $dy)${isRelative ? " + offset" : ""}, // ${fieldElement.name}");
  }

  static Code _generateAssignSpecRect(FieldElement fieldElement, ConstantReader annotation) {
    final left = generateMeasureCodeFromDesignSpecField(annotation.peek('left')?.objectValue);
    final top = generateMeasureCodeFromDesignSpecField(annotation.peek('top')?.objectValue);

    final rightObj = annotation.peek('right')?.objectValue;
    final bottomObj = annotation.peek('bottom')?.objectValue;
    if (rightObj != null && bottomObj != null) {
      final isRelative = annotation.peek('relative')?.boolValue == true;
      final right = generateMeasureCodeFromDesignSpecField(rightObj);
      final bottom = generateMeasureCodeFromDesignSpecField(bottomObj);

      if (fieldElement.type.getDisplayString(withNullability: false) == 'RelativeRect') {
        return Code("RelativeRect.fromLTRB($left, $top, $right, $bottom), // ${fieldElement.name}");
      } else {
        return Code(
            "Rect.fromLTRB($left, $top, $right, $bottom)${isRelative ? ".shift(offset)" : ""}, // ${fieldElement.name}");
      }
    }
    if (fieldElement.type.getDisplayString(withNullability: false) == 'RelativeRect') {
      throw InvalidGenerationSourceError(
        '`RelativeRect` does not support the definition of width/height.',
        todo: 'Please change field Type.',
      );
    }
    final widthObj = annotation.peek('width')?.objectValue;
    final heightObj = annotation.peek('height')?.objectValue;
    if (widthObj != null && heightObj != null) {
      final isRelative = annotation.peek('relative')?.boolValue == true;
      final width = generateMeasureCodeFromDesignSpecField(widthObj);
      final height = generateMeasureCodeFromDesignSpecField(heightObj);
      return Code(
          "Rect.fromLTWH($left, $top, $width, $height)${isRelative ? ".shift(offset)" : ""}, // ${fieldElement.name}");
    }
    throw InvalidGenerationSourceError(
      'Not Found Valid Arg `Rect`.',
      todo: 'Please change field Type.',
    );
  }

  static Code _generateAssignSpecRRect(FieldElement fieldElement, ConstantReader annotation) {
    final left = generateMeasureCodeFromDesignSpecField(annotation.peek('left')?.objectValue);
    final top = generateMeasureCodeFromDesignSpecField(annotation.peek('top')?.objectValue);
    final radius = generateMeasureCodeFromDesignSpecField(annotation.peek('radius')?.objectValue);
    final rightObj = annotation.peek('right')?.objectValue;
    final bottomObj = annotation.peek('bottom')?.objectValue;
    if (rightObj != null && bottomObj != null) {
      final isRelative = annotation.peek('relative')?.boolValue == true;
      final right = generateMeasureCodeFromDesignSpecField(rightObj);
      final bottom = generateMeasureCodeFromDesignSpecField(bottomObj);
      return Code(
          "RRect.fromLTRBR($left, $top, $right, $bottom, $radius)${isRelative ? ".shift(offset)" : ""}, // ${fieldElement.name}");
    }
    final widthObj = annotation.peek('width')?.objectValue;
    final heightObj = annotation.peek('height')?.objectValue;
    if (widthObj != null && heightObj != null) {
      final isRelative = annotation.peek('relative')?.boolValue == true;
      final width = generateMeasureCodeFromDesignSpecField(widthObj);
      final height = generateMeasureCodeFromDesignSpecField(heightObj);
      return Code(
          "RRect.fromRectAndRadius(Rect.fromLTWH($left, $top, $width, $height), $radius)${isRelative ? ".shift(offset)" : ""}, // ${fieldElement.name}");
    }
    throw InvalidGenerationSourceError(
      'Not Found Valid Arg `RRect`.',
      todo: 'Please change field Type.',
    );
  }

  static Code _generateAssignSpecList(FieldElement fieldElement, ConstantReader annotation) {
    final list = annotation.peek('list')?.listValue;
    if (list == null) {
      throw InvalidGenerationSourceError(
        'Not Found Valid List `${list.runtimeType}`.',
        todo: 'Please change field Type.',
      );
    }
    final listCode = list.map((obj) => generateMeasureCodeFromDesignSpecField(obj)).join(",");
    return Code("<double>[$listCode], // ${fieldElement.name}");
  }

  static Code _generateAssignNestedSpec(FieldElement fieldElement, ConstantReader annotation) {
    final typeName = fieldElement.type.getDisplayString(withNullability: false);

    final width = annotation.peek('designWidth')?.doubleValue ?? 0;
    final widthUpperLimit = annotation.peek('widthUpperLimit')?.doubleValue ?? 0xFFFFFFFF;
    final widthLowerLimit = annotation.peek('widthLowerLimit')?.doubleValue ?? 0;

    final height = annotation.peek('designHeight')?.doubleValue ?? 0;
    final heightUpperLimit = annotation.peek('heightUpperLimit')?.doubleValue ?? 0xFFFFFFFF;
    final heightLowerLimit = annotation.peek('heightLowerLimit')?.doubleValue ?? 0;

    final consistentHeight = annotation.peek('consistentHeight')?.boolValue ?? false;
    final consistentWidth = annotation.peek('consistentWidth')?.boolValue ?? false;

    final widthCode =
        "_measuredMetrics.measureWidth($width, consistent: $consistentWidth).clamp($widthLowerLimit, $widthUpperLimit)";
    final heightCode =
        "_measuredMetrics.measureHeight($height, consistent: $consistentHeight).clamp($heightLowerLimit, $heightUpperLimit)";
    return Code("$typeName.create(Size($widthCode, $heightCode), offset: offset),");
  }

  static Code _generateAssignNestedAspectSpec(
      FieldElement fieldElement, ConstantReader annotation) {
    final typeName = fieldElement.type.getDisplayString(withNullability: false);
    final aspectRatio = annotation.peek('aspectRatio')?.doubleValue;
    final relativeWidthScale = annotation.peek('relativeWidthScale')?.doubleValue;
    final widthUpperLimit = annotation.peek('widthUpperLimit')?.doubleValue ?? 0xFFFFFFFF;
    final widthLowerLimit = annotation.peek('widthLowerLimit')?.doubleValue ?? 0;

    final aspectRatioCode = "${aspectRatio ?? "_measuredMetrics.aspectRatio"}";

    final widthCode =
        "(_measuredMetrics.measuredWidth * ${relativeWidthScale ?? 1.0}).clamp($widthLowerLimit, $widthUpperLimit)";

    return Code(
        "$typeName.create(Size($widthCode, $widthCode / ($aspectRatioCode)), offset: offset),");
  }

  static Code _generateAssignNestedAspectHeightSpec(
      FieldElement fieldElement, ConstantReader annotation) {
    final typeName = fieldElement.type.getDisplayString(withNullability: false);
    final value = annotation.peek('height')?.doubleValue;
    final height = "_measuredMetrics.measureHeight($value)";
    final ratio = annotation.peek('aspectRatio')?.doubleValue;
    return Code(
        "$typeName.create(Size($height * $ratio, $height), offset: offset), // ${fieldElement.name}");
  }

  static Code _generateAssignNestedAspectWidthSpec(
      FieldElement fieldElement, ConstantReader annotation) {
    final typeName = fieldElement.type.getDisplayString(withNullability: false);
    final value = annotation.peek('width')?.doubleValue;
    final width = "_measuredMetrics.measureWidth($value)";
    final ratio = annotation.peek('aspectRatio')?.doubleValue;
    return Code(
        "$typeName.create(Size($width, $width * $ratio), offset: offset), // ${fieldElement.name}");
  }
}
