library;

import 'package:flutter/material.dart';

enum DeviceType {
  mobile,
  tablet,
  desktop,
}

class Breakpoints {
  Breakpoints._();

  static const double mobile = 600;
  static const double tablet = 1024;
  static const double desktop = 1024;

  static const double mobileSmall = 360;
  static const double mobileLarge = 480;
  static const double tabletSmall = 600;
  static const double tabletLarge = 840;
  static const double desktopSmall = 1024;
  static const double desktopMedium = 1440;
  static const double desktopLarge = 1920;
  static const double desktopUltra = 2560;

  static DeviceType getDeviceType(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;
    return getDeviceTypeFromWidth(width);
  }

  static DeviceType getDeviceTypeFromWidth(double width) {
    if (width < mobile) {
      return DeviceType.mobile;
    } else if (width < desktop) {
      return DeviceType.tablet;
    } else {
      return DeviceType.desktop;
    }
  }

  static bool isMobile(BuildContext context) {
    return getDeviceType(context) == DeviceType.mobile;
  }

  static bool isTablet(BuildContext context) {
    return getDeviceType(context) == DeviceType.tablet;
  }

  static bool isDesktop(BuildContext context) {
    return getDeviceType(context) == DeviceType.desktop;
  }

  static bool isTabletOrLarger(BuildContext context) {
    final DeviceType type = getDeviceType(context);
    return type == DeviceType.tablet || type == DeviceType.desktop;
  }

  static bool isMobileOrTablet(BuildContext context) {
    final DeviceType type = getDeviceType(context);
    return type == DeviceType.mobile || type == DeviceType.tablet;
  }

  static T adaptive<T>({
    required BuildContext context,
    required T mobile,
    T? tablet,
    T? desktop,
  }) {
    final DeviceType deviceType = getDeviceType(context);

    switch (deviceType) {
      case DeviceType.mobile:
        return mobile;
      case DeviceType.tablet:
        return tablet ?? mobile;
      case DeviceType.desktop:
        return desktop ?? tablet ?? mobile;
    }
  }

  static int getGridColumns(BuildContext context) {
    final double width = MediaQuery.of(context).size.width;

    if (width < mobileSmall) {
      return 1;
    } else if (width < mobileLarge) {
      return 2;
    } else if (width < tabletSmall) {
      return 3;
    } else if (width < tabletLarge) {
      return 4;
    } else if (width < desktopSmall) {
      return 6;
    } else if (width < desktopMedium) {
      return 8;
    } else {
      return 12;
    }
  }

  static EdgeInsets getAdaptivePadding(BuildContext context) {
    return adaptive<EdgeInsets>(
      context: context,
      mobile: const EdgeInsets.all(16),
      tablet: const EdgeInsets.all(24),
      desktop: const EdgeInsets.all(32),
    );
  }

  static EdgeInsets getHorizontalPadding(BuildContext context) {
    return adaptive<EdgeInsets>(
      context: context,
      mobile: const EdgeInsets.symmetric(horizontal: 16),
      tablet: const EdgeInsets.symmetric(horizontal: 32),
      desktop: const EdgeInsets.symmetric(horizontal: 48),
    );
  }

  static double getSpacing(BuildContext context) {
    return adaptive<double>(
      context: context,
      mobile: 8,
      tablet: 12,
      desktop: 16,
    );
  }

  static double getFontScale(BuildContext context) {
    return adaptive<double>(
      context: context,
      mobile: 1.0,
      tablet: 1.1,
      desktop: 1.0,
    );
  }
}

extension ResponsiveContext on BuildContext {
  DeviceType get deviceType => Breakpoints.getDeviceType(this);

  bool get isMobile => Breakpoints.isMobile(this);

  bool get isTablet => Breakpoints.isTablet(this);

  bool get isDesktop => Breakpoints.isDesktop(this);

  bool get isTabletOrLarger => Breakpoints.isTabletOrLarger(this);

  bool get isMobileOrTablet => Breakpoints.isMobileOrTablet(this);

  double get screenWidth => MediaQuery.of(this).size.width;

  double get screenHeight => MediaQuery.of(this).size.height;

  T adaptive<T>({
    required T mobile,
    T? tablet,
    T? desktop,
  }) {
    return Breakpoints.adaptive<T>(
      context: this,
      mobile: mobile,
      tablet: tablet,
      desktop: desktop,
    );
  }
}
