// lib/utils/validators.dart
import 'package:flutter/services.dart';

/// Common validators for Indian IDs, payments, and typical form fields.
class Validators {
  // -----------------------------
  // Regexes (compiled once)
  // -----------------------------
  static final RegExp _panRegex = RegExp(r'^[A-Z]{5}[0-9]{4}[A-Z]$');
  // GSTIN: 2-digit/valid state code, PAN, entity code (1-9A-Z), 'Z', checksum (0-9A-Z)
  static final RegExp _gstRegex = RegExp(
    r'^(0[1-9]|1[0-9]|2[0-9]|3[0-7])[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$',
  );
  // Aadhaar digits only
  static final RegExp _aadhaarRegex = RegExp(r'^[2-9]\d{11}$');
  // Name (letters + spaces + dots + hyphen/apostrophe)
  static final RegExp _nameRegex = RegExp(r"^[A-Za-z][A-Za-z .'\-]{1,49}$");
  // Email (generic)
  static final RegExp _emailRegex =
      RegExp(r"^[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}$");
  // Indian mobile
  static final RegExp _mobileRegex = RegExp(r'^[6-9]\d{9}$');
  // Pincode (India: 6 digits starting 1–9)
  static final RegExp _pincodeRegex = RegExp(r'^[1-9][0-9]{5}$');
  // IFSC (4 letters + 0 + 6 alphanumeric)
  static final RegExp _ifscRegex = RegExp(r'^[A-Z]{4}0[A-Z0-9]{6}$');
  // Bank account number (9–18 digits)
  static final RegExp _bankAccountRegex = RegExp(r'^\d{9,18}$');
  // UPI ID (name@bank, simple check)
  static final RegExp _upiRegex =
      RegExp(r'^[\w.\-]{2,}@[\w]{2,}$', caseSensitive: false);
  // Strong password (8+ chars, upper, lower, digit, special)
  static final RegExp _passwordRegex =
      RegExp(r'^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$');
  // Date dd/mm/yyyy (basic validation)
  static final RegExp _dateRegex =
      RegExp(r'^([0-2][0-9]|3[0-1])/(0[1-9]|1[0-2])/[0-9]{4}$');
  // URL
  static final RegExp _urlRegex = RegExp(
      r'^(https?:\/\/)?([a-zA-Z0-9.-]+)\.[a-zA-Z]{2,}(:\d+)?(\/\S*)?$');
  // Transaction ID (alphanumeric, dashes/underscores, 8–36 chars)
  static final RegExp _transactionIdRegex =
      RegExp(r'^[A-Za-z0-9\-_]{8,36}$');

  // -----------------------------
  // PAN
  // -----------------------------
  static bool isValidPAN(String? input) {
    if (input == null) return false;
    return _panRegex.hasMatch(input.trim().toUpperCase());
  }

  // -----------------------------
  // GSTIN
  // -----------------------------
  static bool isValidGSTIN(String? input) {
    if (input == null) return false;
    return _gstRegex.hasMatch(_compact(input).toUpperCase());
  }

  // -----------------------------
  // Aadhaar
  // -----------------------------
  static bool isValidAadhaar(String? input, {bool enforceChecksum = true}) {
    if (input == null) return false;
    final a = _digitsOnly(input);
    if (!_aadhaarRegex.hasMatch(a)) return false;
    return enforceChecksum ? _verhoeffValidate(a) : true;
  }

  // -----------------------------
  // Mobile
  // -----------------------------
  static bool isValidIndianMobile(String? input) {
    if (input == null) return false;
    final s = _digitsOnly(input.replaceFirst(RegExp(r'^(?:\+?91|0)'), ''));
    return _mobileRegex.hasMatch(s);
  }

  // -----------------------------
  // Email
  // -----------------------------
  static bool isValidEmail(String? input, {bool gmailOnly = false}) {
    if (input == null) return false;
    final e = input.trim();
    if (!_emailRegex.hasMatch(e)) return false;
    if (!gmailOnly) return true;
    final domain = e.split('@').last.toLowerCase();
    return domain == 'gmail.com' || domain == 'googlemail.com';
  }

  static bool isValidGmail(String? input) =>
      isValidEmail(input, gmailOnly: true);

  // -----------------------------
  // Name
  // -----------------------------
  static bool isValidName(String? input, {int minLen = 2, int maxLen = 50}) {
    if (input == null) return false;
    final s = input.trim();
    if (s.length < minLen || s.length > maxLen) return false;
    return _nameRegex.hasMatch(s);
  }

  // -----------------------------
  // Transaction ID
  // -----------------------------
  static bool isValidTransactionId(String? input) {
    if (input == null) return false;
    return _transactionIdRegex.hasMatch(input.trim());
  }

  // -----------------------------
  // Other fields
  // -----------------------------
  static bool isValidPincode(String? input) =>
      input != null && _pincodeRegex.hasMatch(input.trim());

  static bool isValidIFSC(String? input) =>
      input != null && _ifscRegex.hasMatch(input.trim().toUpperCase());

  static bool isValidBankAccount(String? input) =>
      input != null && _bankAccountRegex.hasMatch(_digitsOnly(input));

  static bool isValidUPI(String? input) =>
      input != null && _upiRegex.hasMatch(input.trim());

  static bool isValidPassword(String? input) =>
      input != null && _passwordRegex.hasMatch(input.trim());

  static bool isValidDate(String? input) =>
      input != null && _dateRegex.hasMatch(input.trim());

  static bool isValidURL(String? input) =>
      input != null && _urlRegex.hasMatch(input.trim());

  // -----------------------------
  // Numbers
  // -----------------------------
  static bool isInt(String? input) =>
      input != null && int.tryParse(input.trim()) != null;

  static bool isDouble(String? input) =>
      input != null && double.tryParse(input.trim()) != null;

  static bool isNumeric(String? input) => isInt(input) || isDouble(input);

  static bool isInRange(num? value,
      {num? min, num? max, bool inclusive = true}) {
    if (value == null) return false;
    if (min != null && (inclusive ? value < min : value <= min)) return false;
    if (max != null && (inclusive ? value > max : value >= max)) return false;
    return true;
  }

  // -----------------------------
  // Flutter-friendly validator lambdas (return null when valid)
  // -----------------------------
  static String? requiredField(String? v, {String fieldName = 'This field'}) =>
      (v == null || v.trim().isEmpty) ? '$fieldName is required' : null;

  static String? panValidator(String? v) =>
      isValidPAN(v) ? null : 'Enter a valid PAN (e.g., ABCDE1234F)';

  static String? gstValidator(String? v, {bool optional = false}) {
    if (optional && (v == null || v.trim().isEmpty)) return null;
    return isValidGSTIN(v) ? null : 'Enter a valid GSTIN';
  }

  static String? aadhaarValidator(String? v) =>
      isValidAadhaar(v) ? null : 'Enter a valid Aadhaar (12 digits)';

  static String? mobileValidator(String? v) =>
      isValidIndianMobile(v) ? null : 'Enter a valid 10-digit mobile';

  static String? emailValidator(String? v, {bool gmailOnly = false}) =>
      isValidEmail(v, gmailOnly: gmailOnly)
          ? null
          : gmailOnly
              ? 'Enter a valid Gmail address'
              : 'Enter a valid email address';

  static String? nameValidator(String? v, {int minLen = 2, int maxLen = 50}) =>
      isValidName(v, minLen: minLen, maxLen: maxLen)
          ? null
          : 'Enter a valid name ($minLen–$maxLen chars)';

  static String? transactionIdValidator(String? v) =>
      isValidTransactionId(v)
          ? null
          : 'Enter a valid Transaction ID (8–36 chars, letters/numbers)';

  static String? pincodeValidator(String? v) =>
      isValidPincode(v) ? null : 'Enter a valid 6-digit pincode';

  static String? ifscValidator(String? v) =>
      isValidIFSC(v) ? null : 'Enter a valid IFSC code';

  static String? bankAccountValidator(String? v) =>
      isValidBankAccount(v) ? null : 'Enter a valid bank account (9–18 digits)';

  static String? upiValidator(String? v) =>
      isValidUPI(v) ? null : 'Enter a valid UPI ID';

  static String? passwordValidator(String? v) =>
      isValidPassword(v)
          ? null
          : 'Password must be 8+ chars with upper, lower, digit, special';

  static String? dateValidator(String? v) =>
      isValidDate(v) ? null : 'Enter date in dd/mm/yyyy format';

  static String? urlValidator(String? v) =>
      isValidURL(v) ? null : 'Enter a valid URL';

  // -----------------------------
  // Helpers
  // -----------------------------
  static String _digitsOnly(String s) => s.replaceAll(RegExp(r'\D'), '');
  static String _compact(String s) => s.replaceAll(RegExp(r'\s'), '');

  // -----------------------------
  // Verhoeff checksum (for Aadhaar)
  // -----------------------------
  static const List<List<int>> _verhoeffD = [
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    [1, 2, 3, 4, 0, 6, 7, 8, 9, 5],
    [2, 3, 4, 0, 1, 7, 8, 9, 5, 6],
    [3, 4, 0, 1, 2, 8, 9, 5, 6, 7],
    [4, 0, 1, 2, 3, 9, 5, 6, 7, 8],
    [5, 9, 8, 7, 6, 0, 4, 3, 2, 1],
    [6, 5, 9, 8, 7, 1, 0, 4, 3, 2],
    [7, 6, 5, 9, 8, 2, 1, 0, 4, 3],
    [8, 7, 6, 5, 9, 3, 2, 1, 0, 4],
    [9, 8, 7, 6, 5, 4, 3, 2, 1, 0],
  ];
  static const List<List<int>> _verhoeffP = [
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
    [1, 5, 7, 6, 2, 8, 3, 0, 9, 4],
    [5, 8, 0, 3, 7, 9, 6, 1, 4, 2],
    [8, 9, 1, 6, 0, 4, 3, 5, 2, 7],
    [9, 4, 5, 3, 1, 2, 6, 8, 7, 0],
    [4, 2, 8, 6, 5, 7, 3, 9, 0, 1],
    [2, 7, 9, 3, 8, 0, 5, 4, 1, 6],
    [7, 0, 4, 6, 9, 1, 2, 3, 5, 8],
  ];

  static bool _verhoeffValidate(String numStr) {
    int c = 0;
    final rev = numStr.split('').reversed.map(int.parse).toList();
    for (int i = 0; i < rev.length; i++) {
      c = _verhoeffD[c][_verhoeffP[(i % 8)][rev[i]]];
    }
    return c == 0;
  }
}

/// Common input formatters/masks useful in TextFields.
class InputFormatters {
  static final digitsOnly = FilteringTextInputFormatter.digitsOnly;
  static final upperAlnum =
      FilteringTextInputFormatter.allow(RegExp(r'[A-Z0-9]'));
  static final upperLetters =
      FilteringTextInputFormatter.allow(RegExp(r'[A-Z]'));
  static final name =
      FilteringTextInputFormatter.allow(RegExp(r"[A-Za-z .'\-]"));
  static final alnumWithSpace =
      FilteringTextInputFormatter.allow(RegExp(r"[A-Za-z0-9 ]"));
  static LengthLimitingTextInputFormatter maxLen(int n) =>
      LengthLimitingTextInputFormatter(n);
}
