
//  Created by Tencent on 2023/06/09.
//  Copyright © 2023 Tencent. All rights reserved.
#import <objc/runtime.h>
#import "UIView+TUILayout.h"

@implementation UIView (TUILayout)

#pragma mark - frame
- (void)setMm_x:(CGFloat)mm_x {
    CGRect frame = self.frame;
    frame.origin.x = mm_x;
    self.frame = frame;
}

- (CGFloat)mm_x {
    return self.frame.origin.x;
}

- (void)setMm_y:(CGFloat)mm_y {
    CGRect frame = self.frame;
    frame.origin.y = mm_y;
    self.frame = frame;
}
- (CGFloat)mm_y {
    return self.frame.origin.y;
}
- (void)setMm_w:(CGFloat)mm_w {
    CGRect frame = self.frame;
    frame.size.width = mm_w;
    self.frame = frame;
}

- (CGFloat)mm_w {
    return self.frame.size.width;
}

- (void)setMm_h:(CGFloat)mm_h {
    CGRect frame = self.frame;
    frame.size.height = mm_h;
    self.frame = frame;
}

- (CGFloat)mm_h {
    return self.frame.size.height;
}

- (CGPoint)mm_origin {
    return self.frame.origin;
}

- (void)setMm_origin:(CGPoint)mm_origin {
    CGRect frame = self.frame;
    frame.origin = mm_origin;
    self.frame = frame;
}

- (CGSize)mm_size {
    return self.frame.size;
}

- (void)setMm_size:(CGSize)size {
    CGRect frame = self.frame;
    frame.size = size;
    self.frame = frame;
}

- (CGFloat)mm_centerX {
    return self.center.x;
}

- (CGFloat)mm_centerY {
    return self.center.y;
}

- (void)setMm_centerX:(CGFloat)mm_centerX {
    CGPoint center = self.center;
    center.x = mm_centerX;
    self.center = center;
}

- (void)setMm_centerY:(CGFloat)mm_centerY {
    CGPoint center = self.center;
    center.y = mm_centerY;
    self.center = center;
}

- (CGFloat)mm_r {
    NSCAssert(self.superview, @"must add subview first");
    return self.superview.mm_w - self.mm_maxX;
}

- (void)setMm_r:(CGFloat)mm_r {
    self.mm_x += self.mm_r - mm_r;
}

- (CGFloat)mm_b {
    NSCAssert(self.superview, @"must add subview first");
    return self.superview.mm_h - self.mm_maxY;
}

- (void)setMm_b:(CGFloat)mm_b {
    self.mm_y += self.mm_b - mm_b;
}

- (CGFloat)mm_maxY {
    return CGRectGetMaxY(self.frame);
}
- (CGFloat)mm_minY {
    return CGRectGetMinY(self.frame);
}
- (CGFloat)mm_maxX {
    return CGRectGetMaxX(self.frame);
}
- (CGFloat)mm_minX {
    return CGRectGetMinX(self.frame);
}

#pragma mark - chain call

- (UIView * (^)(CGFloat))mm_top {
    @tui_mm_weakify(self);
    return ^(CGFloat m_top) {
      @tui_mm_strongify(self);
      self.mm_y = m_top;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm_bottom {
    @tui_mm_weakify(self);
    return ^(CGFloat m_bottom) {
      @tui_mm_strongify(self);
      self.mm_b = m_bottom;
      return self;
    };
}
- (UIView * (^)(CGFloat))mm_flexToBottom {
    @tui_mm_weakify(self);
    return ^(CGFloat m_flexToBottom) {
      @tui_mm_strongify(self);
      self.mm_h += self.mm_b - m_flexToBottom;
      return self;
    };
}
- (UIView * (^)(CGFloat))mm_left {
    @tui_mm_weakify(self);
    return ^(CGFloat m_left) {
      @tui_mm_strongify(self);
      self.mm_x = m_left;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm_right {
    @tui_mm_weakify(self);
    return ^(CGFloat m_right) {
      @tui_mm_strongify(self);
      self.mm_r = m_right;
      return self;
    };
}
- (UIView * (^)(CGFloat))mm_flexToRight {
    @tui_mm_weakify(self);
    return ^(CGFloat m_flexToRight) {
      @tui_mm_strongify(self);
      self.mm_w += self.mm_r - m_flexToRight;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm_width {
    @tui_mm_weakify(self);
    return ^(CGFloat m_width) {
      @tui_mm_strongify(self);
      self.mm_w = m_width;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm_height {
    @tui_mm_weakify(self);
    return ^(CGFloat m_height) {
      @tui_mm_strongify(self);
      self.mm_h = m_height;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm__centerX {
    @tui_mm_weakify(self);
    return ^(CGFloat x) {
      @tui_mm_strongify(self);
      NSAssert(self.mm_w, @"must set width first");
      self.mm_centerX = x;
      return self;
    };
}

- (UIView * (^)(CGFloat))mm__centerY {
    @tui_mm_weakify(self);
    return ^(CGFloat y) {
      @tui_mm_strongify(self);
      NSAssert(self.mm_h, @"must set height first");
      self.mm_centerY = y;
      return self;
    };
}

- (UIView * (^)(void))tui_mm_center {
    @tui_mm_weakify(self);
    return ^{
      @tui_mm_strongify(self);
      if (self.superview) {
          self.mm_centerX = self.superview.mm_w / 2;
          self.mm_centerY = self.superview.mm_h / 2;
      }
      return self;
    };
}

- (UIView * (^)(void))mm_fill {
    @tui_mm_weakify(self);
    return ^{
      @tui_mm_strongify(self);
      if (self.superview) {
          self.mm_x = self.mm_y = 0;
          self.mm_w = self.superview.mm_w;
          self.mm_h = self.superview.mm_h;
      }
      return self;
    };
}

- (UIView * (^)(void))mm_sizeToFit {
    @tui_mm_weakify(self);
    return ^{
      @tui_mm_strongify(self);
      [self sizeToFit];
      return self;
    };
}
- (UIView * (^)(CGFloat w, CGFloat h))mm_sizeToFitThan {
    @tui_mm_weakify(self);
    return ^(CGFloat w, CGFloat h) {
      @tui_mm_strongify(self);
      [self sizeToFit];
      if (self.mm_w < w) self.mm_w = w;
      if (self.mm_h < h) self.mm_h = h;
      return self;
    };
}

- (UIView * (^)(CGFloat space))mm_hstack {
    @tui_mm_weakify(self);
    return ^(CGFloat space) {
      @tui_mm_strongify(self);
      if (self.mm_sibling) {
          self.mm__centerY(self.mm_sibling.mm_centerY).mm_left(self.mm_sibling.mm_maxX + space);
      }
      return self;
    };
}

- (UIView * (^)(CGFloat space))mm_vstack {
    @tui_mm_weakify(self);
    return ^(CGFloat space) {
      @tui_mm_strongify(self);
      if (self.mm_sibling) {
          self.mm__centerX(self.mm_sibling.mm_centerX).mm_top(self.mm_sibling.mm_maxY + space);
      }
      return self;
    };
}

- (UIView *)mm_sibling {
    NSUInteger idx = [self.superview.subviews indexOfObject:self];
    if (idx == 0 || idx == NSNotFound) return nil;
    return self.superview.subviews[idx - 1];
}

- (UIViewController *)mm_viewController {
    UIView *view = self;
    while (view) {
        UIResponder *nextResponder = [view nextResponder];
        if ([nextResponder isKindOfClass:[UIViewController class]]) {
            return (UIViewController *)nextResponder;
        }
        view = view.superview;
    }
    return nil;
}

static void *gTUIViewLayoutMethodPropertyBottomGap = &gTUIViewLayoutMethodPropertyBottomGap;
static void *gTUIViewLayoutMethodPropertyTopGap = &gTUIViewLayoutMethodPropertyTopGap;
static void *gTUIViewLayoutMethodPropertyLeftGap = &gTUIViewLayoutMethodPropertyLeftGap;
static void *gTUIViewLayoutMethodPropertyRightGap = &gTUIViewLayoutMethodPropertyRightGap;

- (CGFloat)mm_safeAreaBottomGap {
    NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyBottomGap);
    if (gap == nil) {
        if (@available(iOS 11, *)) {
            if (self.superview.safeAreaLayoutGuide.layoutFrame.size.height > 0) {
                gap = @((self.superview.mm_h - self.superview.safeAreaLayoutGuide.layoutFrame.origin.y -
                         self.superview.safeAreaLayoutGuide.layoutFrame.size.height));
            } else {
                gap = nil;
            }
        } else {
            gap = @(0);
        }
        objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyBottomGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return gap.floatValue;
}

- (CGFloat)mm_safeAreaTopGap {
    NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyTopGap);
    if (gap == nil) {
        if (@available(iOS 11, *)) {
            gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.y);
        } else {
            gap = @(0);
        }
        objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyTopGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return gap.floatValue;
}

- (CGFloat)mm_safeAreaLeftGap {
    NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyLeftGap);
    if (gap == nil) {
        if (@available(iOS 11, *)) {
            gap = @(self.superview.safeAreaLayoutGuide.layoutFrame.origin.x);
        } else {
            gap = @(0);
        }
        objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyLeftGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return gap.floatValue;
}

- (CGFloat)mm_safeAreaRightGap {
    NSNumber *gap = objc_getAssociatedObject(self, gTUIViewLayoutMethodPropertyRightGap);
    if (gap == nil) {
        if (@available(iOS 11, *)) {
            gap =
                @((self.superview.mm_w - self.superview.safeAreaLayoutGuide.layoutFrame.origin.x - self.superview.safeAreaLayoutGuide.layoutFrame.size.width));
        } else {
            gap = @(0);
        }
        objc_setAssociatedObject(self, gTUIViewLayoutMethodPropertyRightGap, gap, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    }
    return gap.floatValue;
}

@end
