import 'dart:convert';

import 'package:flutter/material.dart';
import 'base_field.dart';
import '../ui/entity_form.dart';

import 'custom_text_field.dart';
import 'number_field.dart' as shared_number;
import 'date_field.dart' as shared_date;
import 'currency_field.dart';
import 'qr_code_field.dart';
import 'barcode_field.dart';

/// FieldGroupField
/// - Visual group that renders multiple sub-inputs inside a styled container
/// - Uses EntityForm's composite submit capability via assignByJsonPaths + paths
/// - The group controller stores a JSON string of path->value; on submit, EntityForm
///   assigns each value into the request body by its json path.
class FieldGroupField extends BaseField {
  final String fieldKey;
  final String label;
  final String hint;
  final bool isRequired;
  final List<GroupSubField>? subFields;
  // Schema-driven: field name -> type (e.g., 'text', 'number', 'date', 'currency', 'qrcode', 'barcode')
  final String? groupPrefix; // e.g., 'primary'
  final Map<String, String>? schema;

  FieldGroupField({
    required this.fieldKey,
    required this.label,
    this.hint = '',
    this.isRequired = false,
    this.subFields,
    this.groupPrefix,
    this.schema,
  });

  @override
  String? Function(String?)? get validator => (v) {
        if (!isRequired) return null;
        final fields = _effectiveSubFields;
        if (fields.any((sf) => sf.isRequired)) {
          final scope = _scope;
          if (scope == null) return null;
          for (final sf in fields) {
            if (!sf.isRequired) continue;
            final c = scope.controllers[sf.path];
            if (c == null || c.text.trim().isEmpty) {
              return 'Please complete required fields';
            }
          }
        }
        return null;
      };

  static EntityFormScope? get _scope => _EntityFormScopeAccessor.scope;

  @override
  Map<String, dynamic>? get customProperties => {
        'excludeFromSubmit': true,
        'assignByJsonPaths': true,
        'paths': _effectiveSubFields.map((e) => e.path).toList(),
      };

  @override
  Widget buildField({
    required TextEditingController controller,
    required ColorScheme colorScheme,
    VoidCallback? onChanged,
  }) {
    return _EntityFormScopeAccessor(
      builder: (scope) {
        final fields = _effectiveSubFields;
        return Container(
          decoration: BoxDecoration(
            color: colorScheme.surface,
            borderRadius: BorderRadius.circular(16),
            border:
                Border.all(color: colorScheme.outlineVariant.withOpacity(0.4)),
            boxShadow: [
              BoxShadow(
                color: colorScheme.shadow.withOpacity(0.04),
                blurRadius: 10,
                offset: const Offset(0, 6),
              ),
            ],
          ),
          child: Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  label,
                  style: TextStyle(
                    color: colorScheme.onSurface,
                    fontWeight: FontWeight.w700,
                    fontSize: 16,
                  ),
                ),
                if (hint.isNotEmpty) ...[
                  const SizedBox(height: 4),
                  Text(
                    hint,
                    style: TextStyle(
                      color: colorScheme.onSurfaceVariant,
                      fontSize: 12,
                    ),
                  ),
                ],
                const SizedBox(height: 12),
                ...fields.map((sf) => _buildSubField(
                    scope, sf, colorScheme, controller, onChanged)),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget _buildSubField(
    EntityFormScope? scope,
    GroupSubField sf,
    ColorScheme colorScheme,
    TextEditingController groupController,
    VoidCallback? onChanged,
  ) {
    final existing = scope?.controllers[sf.path];
    final TextEditingController controller =
        existing ?? TextEditingController();
    // Ensure controller is registered in scope for inner fields
    if (scope != null && existing == null) {
      scope.controllers[sf.path] = controller;
    }
    // Prefill subfield from group's encoded initial JSON (built by EntityForm)
    if (controller.text.isEmpty && groupController.text.isNotEmpty) {
      try {
        final decoded = const JsonDecoder().convert(groupController.text);
        if (decoded is Map<String, dynamic>) {
          final dynamic v = decoded[sf.path];
          if (v != null && v.toString().isNotEmpty) {
            controller.text = v.toString();
          }
        }
      } catch (_) {
        // Ignore decode errors; groupController may not be JSON yet
      }
    }
    controller.addListener(() {
      // Encode all subfield values into the group controller for submit mapping
      final Map<String, dynamic> map = {};
      for (final s in _effectiveSubFields) {
        final c = scope?.controllers[s.path];
        if (c != null && c.text.isNotEmpty) {
          map[s.path] = c.text.trim();
        }
      }
      groupController.text = _encode(map);
      onChanged?.call();
      scope?.notifyParent();
    });

    // Build appropriate shared field by type, but render it inline
    final BaseField field = _toSharedField(sf);
    return Padding(
      padding: const EdgeInsets.only(bottom: 12),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          if (sf.label.isNotEmpty)
            Padding(
              padding: const EdgeInsets.only(bottom: 6),
              child: Text(
                sf.label,
                style: TextStyle(
                  color: colorScheme.onSurface,
                  fontWeight: FontWeight.w600,
                  fontSize: 13,
                ),
              ),
            ),
          field.buildField(
            controller: controller,
            colorScheme: colorScheme,
            onChanged: onChanged,
          ),
        ],
      ),
    );
  }

  String _encode(Map<String, dynamic> map) => const JsonEncoder().convert(map);

  List<GroupSubField> get _effectiveSubFields {
    if (subFields != null && subFields!.isNotEmpty) return subFields!;
    final List<GroupSubField> out = [];
    final prefix = groupPrefix ?? '';
    final schemaMap = schema ?? const {};
    schemaMap.forEach((name, type) {
      final path = prefix.isEmpty ? name : '$prefix.$name';
      out.add(GroupSubField(
        path: path,
        label: _capitalize(name.replaceAll('_', ' ')),
        hint: '',
        keyboardType: _keyboardFromType(type),
        isRequired: false,
        type: type,
      ));
    });
    return out;
  }

  TextInputType _keyboardFromType(String type) {
    switch (type.toLowerCase()) {
      case 'number':
      case 'currency':
        return TextInputType.number;
      default:
        return TextInputType.text;
    }
  }

  String _capitalize(String s) {
    if (s.isEmpty) return s;
    return s[0].toUpperCase() + s.substring(1);
  }

  BaseField _toSharedField(GroupSubField sf) {
    final t = (sf.type ?? 'text').toLowerCase();
    switch (t) {
      case 'number':
        return shared_number.NumberField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
      case 'date':
        return shared_date.DateField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
      case 'currency':
        return CurrencyField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
      case 'qrcode':
      case 'qr':
        return QRCodeField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
      case 'barcode':
        return BarcodeField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
      case 'text':
      default:
        return CustomTextField(
          fieldKey: sf.path,
          label: sf.label,
          hint: sf.hint,
          isRequired: sf.isRequired,
        );
    }
  }
}

class GroupSubField {
  final String path; // JSON path for EntityForm to assign during submit
  final String label;
  final String hint;
  final TextInputType keyboardType;
  final bool isRequired;
  final String? type; // schema type identifier

  GroupSubField({
    required this.path,
    required this.label,
    this.hint = '',
    this.keyboardType = TextInputType.text,
    this.isRequired = false,
    this.type,
  });
}

/// Helper to access EntityFormScope in a builder without changing base components
class _EntityFormScopeAccessor extends StatefulWidget {
  final Widget Function(EntityFormScope? scope) builder;
  const _EntityFormScopeAccessor({required this.builder});

  static EntityFormScope? get scope => _lastScope;
  static EntityFormScope? _lastScope;

  @override
  State<_EntityFormScopeAccessor> createState() =>
      _EntityFormScopeAccessorState();
}

class _EntityFormScopeAccessorState extends State<_EntityFormScopeAccessor> {
  @override
  Widget build(BuildContext context) {
    final scope = EntityFormScope.of(context);
    _EntityFormScopeAccessor._lastScope = scope;
    return widget.builder(scope);
  }
}
