//  CalendarView.mm

#import "CalendarView.h"
#import "CalendarDayCell.h"
#import "NSDate+CalendarHelpers.h"

@interface CalendarView () <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>

@property (nonatomic, strong) UILabel *monthLabel;
@property (nonatomic, strong) UIButton *leftBtn;
@property (nonatomic, strong) UIButton *rightBtn;
@property (nonatomic, strong) UICollectionView *collectionView;
@property (nonatomic, strong) NSDate *displayedMonth; // first day of month
@property (nonatomic, strong) NSArray<NSString*> *weekdaySymbols; // Sun..Sat

@end

@implementation CalendarView

static NSString * const kDayCellId = @"kDayCellId";
static const CGFloat kWeekdayHeaderHeight = 28;
static const NSInteger kColumns = 7;

- (instancetype)initWithFrame:(CGRect)frame {
    if (self = [super initWithFrame:frame]) {
        [self commonInit];
    }
    return self;
}

- (void)commonInit {
    self.backgroundColor = [UIColor clearColor];

    // Month header
    self.leftBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.leftBtn setTitle:@"‹" forState:UIControlStateNormal];
    self.leftBtn.titleLabel.font = [UIFont systemFontOfSize:26];
    [self.leftBtn addTarget:self action:@selector(prevMonth) forControlEvents:UIControlEventTouchUpInside];
    self.leftBtn.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:self.leftBtn];

    self.rightBtn = [UIButton buttonWithType:UIButtonTypeSystem];
    [self.rightBtn setTitle:@"›" forState:UIControlStateNormal];
    self.rightBtn.titleLabel.font = [UIFont systemFontOfSize:26];
    [self.rightBtn addTarget:self action:@selector(nextMonth) forControlEvents:UIControlEventTouchUpInside];
    self.rightBtn.translatesAutoresizingMaskIntoConstraints = NO;
    [self addSubview:self.rightBtn];

    self.monthLabel = [[UILabel alloc] init];
    self.monthLabel.translatesAutoresizingMaskIntoConstraints = NO;
    self.monthLabel.textAlignment = NSTextAlignmentCenter;
    self.monthLabel.font = [UIFont systemFontOfSize:16 weight:UIFontWeightMedium];
    [self addSubview:self.monthLabel];

    // Weekday header
    NSCalendar *cal = [NSCalendar currentCalendar];
    self.weekdaySymbols = [cal shortWeekdaySymbols]; // Sun Mon ...
    // Collection view for weekdays + days (we'll render weekdays in supplementary header)
    UICollectionViewFlowLayout *layout = [[UICollectionViewFlowLayout alloc] init];
    layout.minimumInteritemSpacing = 0;
    layout.minimumLineSpacing = 8;
    self.collectionView = [[UICollectionView alloc] initWithFrame:CGRectZero collectionViewLayout:layout];
    self.collectionView.translatesAutoresizingMaskIntoConstraints = NO;
    self.collectionView.backgroundColor = [UIColor clearColor];
    [self.collectionView registerClass:[CalendarDayCell class] forCellWithReuseIdentifier:kDayCellId];
    self.collectionView.dataSource = self;
    self.collectionView.delegate = self;
    [self addSubview:self.collectionView];

    // weekday labels row
    UIStackView *weekdayRow = [[UIStackView alloc] init];
    weekdayRow.translatesAutoresizingMaskIntoConstraints = NO;
    weekdayRow.axis = UILayoutConstraintAxisHorizontal;
    weekdayRow.distribution = UIStackViewDistributionFillEqually;
    weekdayRow.alignment = UIStackViewAlignmentCenter;
    weekdayRow.spacing = 0;
    for (NSString *sym in self.weekdaySymbols) {
        UILabel *lbl = [[UILabel alloc] init];
        lbl.text = sym;
        lbl.font = [UIFont systemFontOfSize:12 weight:UIFontWeightRegular];
        lbl.textColor = [UIColor colorWithWhite:0.5 alpha:1.0];
        lbl.textAlignment = NSTextAlignmentCenter;
        [weekdayRow addArrangedSubview:lbl];
    }
    [self addSubview:weekdayRow];

    // layout constraints
    [NSLayoutConstraint activateConstraints:@[
        [self.leftBtn.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:8],
        [self.leftBtn.topAnchor constraintEqualToAnchor:self.topAnchor constant:4],
        [self.leftBtn.widthAnchor constraintEqualToConstant:36],
        [self.leftBtn.heightAnchor constraintEqualToConstant:36],

        [self.rightBtn.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-8],
        [self.rightBtn.topAnchor constraintEqualToAnchor:self.topAnchor constant:4],
        [self.rightBtn.widthAnchor constraintEqualToConstant:36],
        [self.rightBtn.heightAnchor constraintEqualToConstant:36],

        [self.monthLabel.centerXAnchor constraintEqualToAnchor:self.centerXAnchor],
        [self.monthLabel.centerYAnchor constraintEqualToAnchor:self.leftBtn.centerYAnchor],

        [weekdayRow.topAnchor constraintEqualToAnchor:self.leftBtn.bottomAnchor constant:8],
        [weekdayRow.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
        [weekdayRow.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
        [weekdayRow.heightAnchor constraintEqualToConstant:kWeekdayHeaderHeight],

        [self.collectionView.topAnchor constraintEqualToAnchor:weekdayRow.bottomAnchor constant:4],
        [self.collectionView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:0],
        [self.collectionView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:0],
        [self.collectionView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:0],
    ]];

    // default displayed month = today
    self.displayedMonth = [[NSDate date] startOfMonth];
    [self updateMonthLabel];
}

#pragma mark - public
- (void)setDisplayedMonth:(NSDate *)month animated:(BOOL)animated {
    NSDate *targetMonth = animated ? month : [month startOfMonth];

    self.displayedMonth = targetMonth;

    [self updateMonthLabel];
    [self.collectionView reloadData];
}


- (void)updateMonthLabel {
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"MMM yyyy";
    self.monthLabel.text = [fmt stringFromDate:self.displayedMonth];
    if ([self.delegate respondsToSelector:@selector(calendarViewMonthChanged:)]) {
        [self.delegate calendarViewMonthChanged:self.displayedMonth];
    }
}

#pragma mark - month nav
- (void)prevMonth {
    self.displayedMonth = [self.displayedMonth dateByAddingMonths:-1];
    [self updateMonthLabel];
    [self.collectionView reloadData];
}

- (void)nextMonth {
    self.displayedMonth = [self.displayedMonth dateByAddingMonths:1];
    [self updateMonthLabel];
    [self.collectionView reloadData];
}

#pragma mark - collection data helpers

- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
    return 1;
}

// We render a 7xN grid. Count = leading blanks + daysInMonth + trailing blanks to fill rows
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
    NSInteger firstWeekday = [self.displayedMonth weekdayOfFirstDay]; // 1=Sun
    NSInteger blanks = firstWeekday - 1; // number of empty cells before day 1
    NSInteger days = [self.displayedMonth numberOfDaysInMonth];
    NSInteger total = blanks + days;
    // round up to multiple of 7
    NSInteger rem = total % kColumns;
    if (rem != 0) total += (kColumns - rem);
    return total;
}

- (NSDate *)dateForIndexPathItem:(NSInteger)item {
    NSInteger firstWeekday = [self.displayedMonth weekdayOfFirstDay];
    NSInteger blanks = firstWeekday - 1;
    NSInteger dayIndex = item - blanks + 1; // day number, may be out of range
    if (dayIndex < 1 || dayIndex > [self.displayedMonth numberOfDaysInMonth]) {
        return nil;
    }
    NSCalendar *cal = [NSCalendar currentCalendar];
    NSDateComponents *comps = [cal components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:self.displayedMonth];
    comps.day = dayIndex;
    return [cal dateFromComponents:comps];
}

- (NSString *)statusForDate:(NSDate *)date {
    if (!date) return nil;
    NSString *key = [date yyyyMMddString];
    NSDictionary *info = self.markedDates[key];
    if (info) {
        NSString *s = info[@"status"];
        if ([s isKindOfClass:[NSString class]]) return s;
    }
    return nil;
}

#pragma mark - collection view datasource
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                          cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
    CalendarDayCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kDayCellId
                                                                      forIndexPath:indexPath];

    NSDate *d = [self dateForIndexPathItem:indexPath.item];
    BOOL inMonth = (d != nil);

    NSNumber *dayNumber = nil;
    if (d) {
        NSCalendar *cal = [NSCalendar currentCalendar];
        NSDateComponents *c = [cal components:NSCalendarUnitDay fromDate:d];
        dayNumber = @(c.day);
    }

    NSString *status = [self statusForDate:d];
    BOOL selected = (d && self.selectedDate && [d isSameDayAsDate:self.selectedDate]);
  
    // Configure day number / selection AFTER color & userInteraction are set
    [cell configureWithDay:dayNumber
                   inMonth:inMonth
                   enabled:YES  // always pass YES here; past/today handled above
                    status:status
                  selected:selected];

    // Reset cell to defaults
    cell.layer.borderWidth = 0;
    cell.layer.borderColor = nil;
    cell.dayLabel.textColor = [UIColor blackColor];
    cell.userInteractionEnabled = YES;

    NSDate *today = [NSDate date];
    NSCalendar *cal = [NSCalendar currentCalendar];

    // Grey out past dates
    if (d && [d compare:today] == NSOrderedAscending) {
        cell.dayLabel.textColor = [UIColor lightGrayColor];
        cell.userInteractionEnabled = NO;
    }
    
    // Highlight today (not selectable)
    BOOL isToday = d && [cal isDate:d inSameDayAsDate:today];
    if (isToday) {
        cell.dayLabel.textColor = [UIColor systemBlueColor];
        cell.userInteractionEnabled = NO;
    }
    return cell;
}

#pragma mark - collection delegate
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    NSDate *d = [self dateForIndexPathItem:indexPath.item];
    if (!d) return;

    NSString *status = [self statusForDate:d];

    if (self.minDate && [d compare:self.minDate] == NSOrderedAscending) return;

    // allow selection only if not unavailable? (you can change)
    // if unavailable, ignore
    if ([status isEqualToString:@"unavailable"]) {
        return;
    }

    self.selectedDate = d;
    [collectionView reloadData];

    if ([self.delegate respondsToSelector:@selector(calendarView:didSelectDate:)]) {
        [self.delegate calendarView:self didSelectDate:d];
    }
}

#pragma mark - layout
- (void)layoutSubviews {
    [super layoutSubviews];
    [self.collectionView.collectionViewLayout invalidateLayout];
}

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath {
    CGFloat totalWidth = collectionView.bounds.size.width;
    CGFloat spacing = 0;
    CGFloat cellWidth = floor((totalWidth - (kColumns - 1) * spacing) / kColumns);
    // height slightly larger to leave space for dot
    return CGSizeMake(cellWidth, cellWidth * 0.9 + 12);
}

@end

