import 'package:fis_measure/interfaces/process/viewports/image_boundary.dart';
import 'package:fis_measure/interfaces/process/physical_coordinates/physical_coordinate.dart';
import 'package:fis_measure/interfaces/date_types/rect_region.dart';
import 'package:fis_measure/interfaces/date_types/point.dart';
import 'package:fis_measure/interfaces/process/viewports/logical_coordinate.dart';
import 'package:fis_measure/interfaces/process/viewports/viewport.dart';
import 'package:fis_measure/interfaces/process/visuals/visual_area.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/painting.dart';
import 'package:vid/us/vid_us_unit.dart';

abstract class ViewPort<TV extends IVisualArea, T extends IPhysicalCoordinate>
    implements IViewPort, ILogicalCoordinate {
  late final IVisualArea _area;
  late final VidUsUnit _xUnit;
  late final VidUsUnit _yUnit;
  late final bool _isFlipHorizontal;
  late final bool _isFlipVertical;
  late final IImageBoundary _imageBoundary;
  late final RectRegion _region;
  T? _physical;

  ViewPort(
    IVisualArea visualArea,
    VidUsUnit xUnit,
    VidUsUnit yUnit,
    bool isFlipHorizontal,
    bool isFlipVertical,
    RectRegion region,
  ) {
    _area = visualArea;
    _xUnit = xUnit;
    _yUnit = yUnit;
    _isFlipHorizontal = isFlipHorizontal;
    _isFlipVertical = isFlipVertical;
    _region = region;
  }

  @override
  IVisualArea get area => _area;

  @override
  IImageBoundary get imageBoundary => _imageBoundary;
  @protected
  set imageBoundary(IImageBoundary value) => _imageBoundary = value;

  @override
  bool get isFlipHorizontal => _isFlipHorizontal;

  @override
  bool get isFlipVertical => _isFlipVertical;

  @override
  T? get physical => _physical;
  @protected
  set physical(T? value) {
    if (value != _physical) {
      _physical = value;
    }
  }

  @override
  RectRegion get region => _region;

  @override
  VidUsUnit get xUnit => _xUnit;

  @override
  VidUsUnit get yUnit => _yUnit;

  @override
  DPoint convert(DPoint point) {
    double x = point.x * region.width;
    double y = point.y * region.height;
    x /= area.displayRegion.width;
    y /= area.displayRegion.height;
    return DPoint(x, y);
    // return DPoint(point.x * region.width, point.y * region.height);
  }

  Size get convertBoundary {
    return Size(
      region.width / area.displayRegion.width,
      region.height / area.displayRegion.height,
    );
  }

  @override
  DPoint convertBack(DPoint point) {
    double x = point.x / region.width;
    double y = point.y / region.height;
    x *= area.displayRegion.width;
    y *= area.displayRegion.height;
    return DPoint(x, y);
    // return DPoint(point.x / region.width, point.y / region.height);
  }
}