// DashboardViewController.mm
#import "DashboardViewController.h"
#import "DashboardHeaderView.h"
#import <CoreGraphics/CoreGraphics.h>
#import <objc/runtime.h>
#import "PlanViewController.h"
#import "DashboardAPIClient.h"
#import "IssueDetailViewController.h"
#import "IssuesViewController.h"
#import "AppointmentViewController.h"
#import "AppointmentDetailsViewController.h"

@interface DashboardViewController ()

@property (nonatomic, strong) NSArray *appointments;
@property (nonatomic, strong) NSArray *issues;
@property (nonatomic, assign) BOOL hasPendingAccess;
@property (nonatomic, assign) BOOL hasSignOff;
@property (nonatomic, strong) NSString *strContactlessHandoverStatus;
@property (nonatomic, strong) NSString *strContactlessFormUrl;
@property (nonatomic, strong) NSString *strPendingAccessReminder;
@property (nonatomic, assign) BOOL bln_Block_Handover;
@property (nonatomic, assign) BOOL bln_Block_Inspection;
@property (nonatomic, assign) NSInteger intPOACount;
@property (nonatomic, assign) NSInteger intPendingAccessCount;
@property (nonatomic, assign) BOOL bln_ReminderPA;
@property (nonatomic, assign) BOOL bln_POASignOff;
@property (nonatomic, strong) NSString *projectCode;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) UIImage *headerBackgroundImage;
@property (nonatomic, strong) NSArray *announcements;
@property (nonatomic, strong) UIView *loadingOverlay;
@property (nonatomic, strong) UIActivityIndicatorView *spinner;

@end

@implementation DashboardViewController {
    DashboardHeaderView *_headerView;
    UIScrollView *_scrollView;
    UIView *_contentContainer, *_inspectionBanner;
    NSMutableDictionary *_sectionViews;
    CGFloat _currentY;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];
    _sectionViews = [NSMutableDictionary dictionary];

    [self setupHeader];
    [self setupScrollContent];
    [self setupFooter];
  
    self.projectCode = @"PTD197656";
    self.projectName = @"Ara E`Residence Dev";

    [self refreshDashboardContent];
    NSLog(@"in viewDidLoad ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
}

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated];
  
  NSLog(@"Dashboard loaded, refreshing data");
  [self refreshDashboardContent];
  NSLog(@"in viewWillAppear ClientID: %@, ClientCode: %@, user_token: %@", self.ClientID, self.ClientCode, self.user_token);
}

#pragma mark - Refresh Logic
- (void)refreshDashboardContent {
    NSLog(@"🔁 Refreshing dashboard content...");

    dispatch_group_t group = dispatch_group_create();
    __block NSDictionary *dashboardData = nil;
    __block NSDictionary *announcementData = nil;

    dispatch_group_enter(group);
    [DashboardAPIClient fetchDashboardInfo:^(NSDictionary *data, NSError *error) {
        if (!error) dashboardData = data;
        dispatch_group_leave(group);
    }];

    dispatch_group_enter(group);
    [DashboardAPIClient fetchAnnouncement:^(NSDictionary *data, NSError *error) {
        if (!error) announcementData = data;
        dispatch_group_leave(group);
    }];

    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        if (dashboardData) [self processDashboardResponse:dashboardData];
        if (announcementData) [self processAnnouncementResponse:announcementData];
        NSLog(@"✅ Dashboard refresh complete");
    });
}


- (void)handlePullToRefresh:(UIRefreshControl *)refreshControl {
    NSLog(@"🔄 Pull-to-refresh triggered");

    [self refreshDashboardContent];

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(), ^{
        [refreshControl endRefreshing];
    });
}

#pragma mark - Layout
- (void)viewDidLayoutSubviews {
    NSLog(@"Header frame: %@", NSStringFromCGRect(_headerView.frame));
    [super viewDidLayoutSubviews];
    UIView *footerView = self.view.subviews.lastObject;
    CGFloat footerHeight = 80.0;
    CGFloat bottomInset = self.view.safeAreaInsets.bottom;
    footerView.frame = CGRectMake(
        0,
        self.view.bounds.size.height - footerHeight - bottomInset,
        self.view.bounds.size.width,
        footerHeight + bottomInset
    );
}

#pragma mark - Header
- (void)setupHeader {
    CGFloat headerHeight = 220.0;
    _headerView = [[DashboardHeaderView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, headerHeight)];
  
    // Remote background image URL
    NSString *remoteHeaderURL = @"https://kitadev.commudesk.com/uploads/marketing_photo/164543837127.png";
    
    // Load image asynchronously so it doesn’t block UI
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSURL *url = [NSURL URLWithString:remoteHeaderURL];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *remoteImage = nil;
        if (data) {
            remoteImage = [UIImage imageWithData:data];
        }
        self.headerBackgroundImage = remoteImage ?: [UIImage imageNamed:@"header_bg"];
        dispatch_async(dispatch_get_main_queue(), ^{
            [_headerView configureWithProjectName:@"Project A"
                                         unitName:@"Unit 3A"
                                 backgroundImage:self.headerBackgroundImage
                                    overlayImage:[UIImage imageNamed:@"overlay"]];
        });
    });
    [self.view addSubview:_headerView];

}

- (void)handleBackButtonTapped {
    NSLog(@"🔙 Back button tapped");
    if (self.presentingViewController) {
        [self dismissViewControllerAnimated:YES completion:nil];
    } else if (self.navigationController) {
        [self.navigationController popViewControllerAnimated:YES];
    }
}

- (void)handleMenuButtonTapped {
    NSLog(@"🍔 Menu button tapped");
}

#pragma mark - Footer
- (void)setupFooter {
    CGFloat footerHeight = 80.0;
    CGFloat bottomInset = self.view.safeAreaInsets.bottom;
    UIView *footerView = [[UIView alloc] initWithFrame:CGRectMake(
        0,
        self.view.bounds.size.height - footerHeight,
        self.view.bounds.size.width,
        footerHeight + bottomInset
    )];
    footerView.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleWidth;
    footerView.backgroundColor = [UIColor whiteColor];
    footerView.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
    footerView.layer.shadowOpacity = 0.8;
    footerView.layer.shadowOffset = CGSizeMake(0, -1);
    [self.view addSubview:footerView];

    NSArray *titles = @[ @"Make Appointment", @"Add Issue", @"View Access Item" ];
    NSArray *icons = @[ @"calendar", @"plus.circle", @"list.bullet" ];
    CGFloat buttonWidth = self.view.bounds.size.width / titles.count;

    for (NSInteger i = 0; i < titles.count; i++) {
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        button.frame = CGRectMake(i * buttonWidth, 0, buttonWidth, footerHeight);
        [button setTitle:titles[i] forState:UIControlStateNormal];
        [button setTitleColor:[UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0] forState:UIControlStateNormal];
        button.titleLabel.font = [UIFont boldSystemFontOfSize:13];
        button.tintColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
        [button setImage:[UIImage systemImageNamed:icons[i]] forState:UIControlStateNormal];

        button.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter;
        button.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
        CGFloat spacing = 6.0;
        CGSize imageSize = button.imageView.frame.size;
        CGSize titleSize = button.titleLabel.frame.size;

        button.titleEdgeInsets = UIEdgeInsetsMake(imageSize.height + spacing, -imageSize.width, 0, 0);
        button.imageEdgeInsets = UIEdgeInsetsMake(-titleSize.height - spacing / 2, 0, 0, -titleSize.width);

        button.tag = i;
        [button addTarget:self action:@selector(footerButtonTapped:) forControlEvents:UIControlEventTouchUpInside];
        [footerView addSubview:button];

        if (i < titles.count - 1) {
            UIView *divider = [[UIView alloc] initWithFrame:CGRectMake((i + 1) * buttonWidth - 0.5, 10, 1, footerHeight - 20)];
            divider.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1.0];
            [footerView addSubview:divider];
        }
    }
}

- (void)footerButtonTapped:(UIButton *)sender {
    switch (sender.tag) {
        case 0: {
          NSLog(@"Navigating to Appointment");
            AppointmentViewController *appointVC = [[AppointmentViewController alloc] init];
            appointVC.projectCode = self.projectCode;
            appointVC.projectName = self.projectName;
            appointVC.projectId = @"8";
            appointVC.modalPresentationStyle = UIModalPresentationFullScreen;
            [self presentViewController:appointVC animated:YES completion:nil];
            break;
        }
        case 1: {
          NSLog(@"Navigating to Plan");
            PlanViewController *planVC = [[PlanViewController alloc] init];
            planVC.projectCode = self.projectCode;
            planVC.projectName = self.projectName;
            planVC.modalPresentationStyle = UIModalPresentationFullScreen;
            [self presentViewController:planVC animated:YES completion:nil];
            break;
        }
        case 2: {
          NSLog(@"Navigating to Access Item");
        }
        default:
            break;
    }
}

#pragma mark - Scroll Content
- (void)setupScrollContent {
    CGFloat topOffset = 220.0;
    _scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(
        0,
        topOffset,
        self.view.bounds.size.width,
        self.view.bounds.size.height - topOffset
    )];
    _scrollView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    _scrollView.backgroundColor = [UIColor clearColor];

    // 🩹 Add dynamic bottom padding so last card doesn’t clip under footer
    CGFloat footerHeight = 80.0 + self.view.safeAreaInsets.bottom;
    _scrollView.contentInset = UIEdgeInsetsMake(0, 0, footerHeight, 0);
    _scrollView.scrollIndicatorInsets = _scrollView.contentInset;

    // === 🌀 Add Pull-to-Refresh ===
    UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
    [refreshControl addTarget:self
                       action:@selector(handlePullToRefresh:)
             forControlEvents:UIControlEventValueChanged];
    if (@available(iOS 10.0, *)) {
        _scrollView.refreshControl = refreshControl;
    } else {
        [_scrollView addSubview:refreshControl];
    }

    [self.view addSubview:_scrollView];

    _contentContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, _scrollView.bounds.size.width, 0)];
    _contentContainer.autoresizingMask = UIViewAutoresizingFlexibleWidth;
    [_scrollView addSubview:_contentContainer];
    _currentY = 16.0;
    [self setupInspectionChecklistBanner];
    if (_currentY == 0) {
        _currentY = 16.0;
    }
}

#pragma mark - Inspection Checklist Banner

- (void)setupInspectionChecklistBanner {
    BOOL blnContactlessHandover = NO;  // mock GLOBALS.BLN_CONTACTLESS_HANDOVER == 1
    BOOL blnInspChecklist = NO;        // mock self.bln_InspChecklist
    NSString *handoverStatus = @"Pending"; // mock self.strContactlessHandoverStatus
    NSInteger daysRemaining = 3;        // mock self.strDays

    // ✅ Condition check
    if (!(blnContactlessHandover && blnInspChecklist && [handoverStatus isEqualToString:@"Pending"])) {
        NSLog(@"ℹ️ No inspection checklist banner required");
        return;
    }

    // Banner container
    _inspectionBanner = [[UIView alloc] initWithFrame:CGRectMake(16, 16, self.view.bounds.size.width - 32, 90)];
    _inspectionBanner.backgroundColor = [UIColor colorWithRed:1.0 green:0.39 blue:0.39 alpha:1.0]; // #FF6464
    _inspectionBanner.layer.cornerRadius = 20;
    _inspectionBanner.clipsToBounds = YES;

    // Tap gesture (simulate button press)
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleInspectionBannerTap)];
    [_inspectionBanner addGestureRecognizer:tap];

    // Title label
    UILabel *titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 16, _inspectionBanner.bounds.size.width - 80, 24)];
    titleLabel.text = @"Submit Unit Inspection Checklist";
    titleLabel.font = [UIFont boldSystemFontOfSize:16];
    titleLabel.textColor = UIColor.whiteColor;
    [_inspectionBanner addSubview:titleLabel];

    // Right arrow icon
    UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"chevron.right"]];
    arrow.tintColor = UIColor.whiteColor;
    arrow.frame = CGRectMake(_inspectionBanner.bounds.size.width - 36, (_inspectionBanner.bounds.size.height - 24)/2, 20, 24);
    arrow.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
    [_inspectionBanner addSubview:arrow];

    // Days remaining pill (optional)
    if (daysRemaining > 0) {
        UIView *pill = [[UIView alloc] initWithFrame:CGRectMake(16, CGRectGetMaxY(titleLabel.frame) + 6, 170, 28)];
        pill.backgroundColor = [UIColor colorWithWhite:0 alpha:0.4];
        pill.layer.cornerRadius = 14;
        pill.clipsToBounds = YES;

        UIImageView *calendarIcon = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"calendar"]];
        calendarIcon.tintColor = UIColor.whiteColor;
        calendarIcon.frame = CGRectMake(8, 4, 20, 20);
        [pill addSubview:calendarIcon];

        UILabel *daysLabel = [[UILabel alloc] initWithFrame:CGRectMake(34, 4, 130, 20)];
        daysLabel.text = [NSString stringWithFormat:@"%ld days remaining", (long)daysRemaining];
        daysLabel.textColor = UIColor.whiteColor;
        daysLabel.font = [UIFont boldSystemFontOfSize:13];
        [pill addSubview:daysLabel];

        [_inspectionBanner addSubview:pill];
    }

    [_contentContainer addSubview:_inspectionBanner];
    _currentY = CGRectGetMaxY(_inspectionBanner.frame) + 16.0;
}

- (void)handleInspectionBannerTap {
    NSLog(@"🟥 Inspection checklist banner tapped");
    [UIView animateWithDuration:0.1 animations:^{
        _inspectionBanner.alpha = 0.6;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.1 animations:^{
            _inspectionBanner.alpha = 1.0;
        }];
    }];
}

#pragma mark - Dashboard Data Processor
- (void)processDashboardResponse:(NSDictionary *)data {
    NSDictionary *appData = data[@"AppData"];
    NSDictionary *mainData = data[@"Data"];

    if (![appData[@"status"] isEqualToString:@"success"] || !mainData) {
        NSLog(@"⚠️ Dashboard status not success: %@", appData[@"message"]);
        return;
    }

    NSArray *appointments = mainData[@"appointment"] ?: @[];
    NSArray *issues = mainData[@"issue_update"] ?: @[];
    NSNumber *paCount = mainData[@"pa_count"];
    NSNumber *poaCount = mainData[@"poa_count"];
    NSString *accessMessage = mainData[@"access_item_message"];
    NSString *accessTNC = mainData[@"access_item_terms_and_condition"];
    NSString *handoverStatus = mainData[@"contactlessHandoverTempStatus"];
    NSString *handoverURL = mainData[@"contactlessHandoverTempURL"];

    BOOL hasPendingAccess = (paCount && paCount.intValue > 0);
    BOOL hasSignOff = (poaCount && poaCount.intValue > 0);

    BOOL blockHandover = NO;
    BOOL blockInspection = NO;
    NSInteger rectificationIssueCount = 0;

    for (NSDictionary *appt in appointments) {
        NSString *type = [appt[@"appointment_type"] lowercaseString];
        NSString *status = [appt[@"status"] lowercaseString];

        if ([type isEqualToString:@"handover"] && [status isEqualToString:@"active"]) {
            blockHandover = YES;
        } else if ([type isEqualToString:@"joint inspection"] && [status isEqualToString:@"active"]) {
            blockInspection = YES;
        } else if ([type isEqualToString:@"rectification"] && ![status isEqualToString:@"cancelled"]) {
            NSArray *issuesList = appt[@"issues"];
            if ([issuesList isKindOfClass:[NSArray class]]) {
                rectificationIssueCount += issuesList.count;
            }
        }
    }

    // If rectification count == pending access count, clear reminder
    if (paCount.intValue == rectificationIssueCount) {
        hasPendingAccess = NO;
    }

    // --- Store results ---
    self.appointments = appointments;
    self.issues = issues;
    self.hasPendingAccess = hasPendingAccess;
    self.hasSignOff = hasSignOff;
    self.intPOACount = poaCount.intValue;
    self.intPendingAccessCount = paCount.intValue;
    self.bln_Block_Handover = blockHandover;
    self.bln_Block_Inspection = blockInspection;
    self.strPendingAccessReminder = accessMessage ?: @"";
    self.strContactlessHandoverStatus = handoverStatus ?: @"";
    self.strContactlessFormUrl = handoverURL ?: @"";

    NSLog(@"✅ Dashboard parsed:");
    NSLog(@"  • Appointments: %lu", (unsigned long)appointments.count);
    NSLog(@"  • Issues: %lu", (unsigned long)issues.count);
    NSLog(@"  • Pending Access: %d", hasPendingAccess);
    NSLog(@"  • POA Count: %ld", (long)self.intPOACount);
    NSLog(@"  • Block Handover: %d", blockHandover);
    NSLog(@"  • Block Inspection: %d", blockInspection);

    dispatch_async(dispatch_get_main_queue(), ^{
        [_headerView configureWithProjectName:self.projectName
                                     unitName:self.projectCode
                             backgroundImage:self.headerBackgroundImage
                                overlayImage:[UIImage imageNamed:@"overlay"]];

        [self refreshDashboardSectionsWithData:mainData];
    });
}

// DashboardViewController.m
- (void)processAnnouncementResponse:(NSDictionary *)data {
    NSLog(@"Handling announcement: %@", data);

    NSDictionary *appData = data[@"AppData"];
    if (![appData[@"status"] isEqualToString:@"success"]) {
        NSLog(@"Announcement fetch failed: %@", appData[@"message"]);
        return;
    }

    // === Combine ===
    NSDictionary *innerData = data[@"Data"] ?: data[@"data"];
    NSArray *client = innerData[@"client_announcement"] ?: @[];
    NSArray *project = innerData[@"project_announcement"] ?: @[];

    NSMutableArray *merged = [NSMutableArray arrayWithArray:client];
    [merged addObjectsFromArray:project];

    // === Sort by date descending ===
    NSArray *sorted = [merged sortedArrayUsingComparator:^NSComparisonResult(NSDictionary *a, NSDictionary *b) {
        NSString *dateA = a[@"date"] ?: @"";
        NSString *dateB = b[@"date"] ?: @"";
        return [dateB compare:dateA];
    }];

    // === Save to property ===
    self.announcements = sorted;

    // === Save to UserDefaults if needed ===
    [[NSUserDefaults standardUserDefaults] setObject:sorted forKey:@"CLIENT_ANNOUNCEMENTS"];
    [[NSUserDefaults standardUserDefaults] synchronize];

    NSLog(@"✅ Stored %lu announcements", (unsigned long)sorted.count);
}

- (void)refreshDashboardSectionsWithData:(NSDictionary *)mainData {
    NSLog(@"🔄 Refreshing dashboard sections...");

    // Remove any old views from scroll
    for (UIView *view in _contentContainer.subviews) {
        [view removeFromSuperview];
    }
    _currentY = 16.0;

    // === PROJECT UPDATES ===
    NSArray *announcements = self.announcements;
    if (announcements.count > 0) {
        UIView *announcementSection = [self buildAnnouncementSection:announcements];
        CGRect f = announcementSection.frame;
        f.origin.y = _currentY;
        announcementSection.frame = f;
        [_contentContainer addSubview:announcementSection];
        _currentY += CGRectGetHeight(announcementSection.frame) + 12;
    }

    // === APPOINTMENTS ===
    NSArray *appointments = mainData[@"appointment"];
    if (appointments.count > 0) {
        UIView *appointmentSection = [self buildAppointmentSection:appointments];
        CGRect f = appointmentSection.frame;
        f.origin.y = _currentY;
        appointmentSection.frame = f;
        [_contentContainer addSubview:appointmentSection];
        _currentY += CGRectGetHeight(appointmentSection.frame) + 12;
    }

    // === ISSUE UPDATES ===
    NSArray *issues = mainData[@"issue_update"];
    if (issues.count > 0) {
        UIView *issueSection = [self buildIssueSection:issues];
        CGRect f = issueSection.frame;
        f.origin.y = _currentY;
        issueSection.frame = f;
        [_contentContainer addSubview:issueSection];
        _currentY += CGRectGetHeight(issueSection.frame) + 16;
    }

    _contentContainer.frame = CGRectMake(0, 0, _scrollView.bounds.size.width, _currentY);
    _scrollView.contentSize = CGSizeMake(_scrollView.bounds.size.width, _currentY);

    NSLog(@"✅ Dashboard UI refreshed with %lu announcements, %lu appointments, %lu issues",
          (unsigned long)announcements.count, (unsigned long)appointments.count, (unsigned long)issues.count);
}

- (UIView *)buildAnnouncementSection:(NSArray *)announcements {
    UIView *section = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 160)];

    // --- Title row ---
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 200, 24)];
    title.text = @"Project Update";
    title.font = [UIFont boldSystemFontOfSize:18];
    title.textColor = [UIColor blackColor];
    title.userInteractionEnabled = YES; // 👈 enable taps

    UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
    [title addGestureRecognizer:titleTap];
    [section addSubview:title];

    UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_green_arrowright"]];
    arrow.frame = CGRectMake(self.view.bounds.size.width - 40, 2, 24, 24);
    [section addSubview:arrow];

    // --- Horizontal scroll for cards ---
    UIScrollView *hScroll = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 40, self.view.bounds.size.width, 110)];
    hScroll.showsHorizontalScrollIndicator = NO;
    CGFloat x = 16;
  
    NSArray *limitedAnnouncements = (announcements.count > 5)
        ? [announcements subarrayWithRange:NSMakeRange(0, 5)]
        : announcements;

    for (NSDictionary *item in limitedAnnouncements) {
        UIView *card = [self makeAnnouncementCard:item];
        CGRect frame = card.frame;
        frame.origin.x = x;
        frame.origin.y = 0;
        card.frame = frame;
        [hScroll addSubview:card];
        x += frame.size.width + 12;
    }
    hScroll.contentSize = CGSizeMake(x, 110);
    [section addSubview:hScroll];

    return section;
}


- (UIView *)buildAppointmentSection:(NSArray *)appointments {
    UIView *section = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 0)];

    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 200, 24)];
    title.text = @"Appointments";
    title.font = [UIFont boldSystemFontOfSize:18];
    [section addSubview:title];
    title.textColor = [UIColor blackColor];
    title.userInteractionEnabled = YES; // 👈 enable taps

    UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
    [title addGestureRecognizer:titleTap];
    UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_green_arrowright"]];
    arrow.frame = CGRectMake(self.view.bounds.size.width - 40, 2, 24, 24);
    [section addSubview:arrow];

    CGFloat y = 34;
    CGFloat cardWidth = self.view.bounds.size.width * 0.9;   // 90% of screen width
    CGFloat xCenter = (self.view.bounds.size.width - cardWidth) / 2.0;
  
    NSArray *limitedAppointments = (appointments.count > 3)
        ? [appointments subarrayWithRange:NSMakeRange(0, 3)]
        : appointments;

    for (NSDictionary *item in limitedAppointments) {
        UIView *card = [self makeAppointmentCard:item width:cardWidth];
        CGRect frame = card.frame;
        frame.origin.x = xCenter;
        frame.origin.y = y;
        card.frame = frame;
        [section addSubview:card];
        y += frame.size.height + 12; // spacing between cards
    }

      section.frame = CGRectMake(0, 0, self.view.bounds.size.width, y + 10);
      return section;
  }

- (UIView *)buildIssueSection:(NSArray *)issues {
    UIView *section = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, 0)];

    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 200, 24)];
    title.text = @"Issue Updates";
    title.font = [UIFont boldSystemFontOfSize:18];
    [section addSubview:title];
    title.textColor = [UIColor blackColor];
    title.userInteractionEnabled = YES; // 👈 enable taps

    UITapGestureRecognizer *titleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(issueHeaderTapped:)];
    [title addGestureRecognizer:titleTap];
    UIImageView *arrow = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"icon_green_arrowright"]];
    arrow.frame = CGRectMake(self.view.bounds.size.width - 40, 2, 24, 24);
    [section addSubview:arrow];

    CGFloat y = 34;
    CGFloat cardWidth = self.view.bounds.size.width * 0.9;   // 90% of screen width
    CGFloat xCenter = (self.view.bounds.size.width - cardWidth) / 2.0;
    
    for (NSDictionary *item in issues) {
        UIView *card = [self makeIssueCard:item width:cardWidth];
        CGRect frame = card.frame;
        frame.origin.x = xCenter;
        frame.origin.y = y;
        card.frame = frame;
        [section addSubview:card];
        y += frame.size.height + 12;
    }

    section.frame = CGRectMake(0, 0, self.view.bounds.size.width, y + 10);
    return section;
}

- (UILabel *)makeSectionTitle:(NSString *)titleText {
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(16, 0, 200, 24)];
    title.text = titleText;
    title.font = [UIFont boldSystemFontOfSize:18];
    title.userInteractionEnabled = YES;
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(sectionHeaderTapped:)];
    [title addGestureRecognizer:tap];
    return title;
}

- (UIView *)makeAnnouncementCard:(NSDictionary *)item {
    UIView *card = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 280, 100)];
    card.backgroundColor = UIColor.whiteColor;
    card.layer.cornerRadius = 8;
    card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
    card.layer.shadowOpacity = 0.3;
    card.layer.shadowOffset = CGSizeMake(0, 1);

    // === 1. Resolve the date field (support both created_at and date) ===
    NSString *dateString = item[@"created_at"] ?: item[@"date"];
    NSString *dateOnly = dateString;

    // === take only the date portion (before space) ===
    if ([dateString containsString:@" "]) {
        dateOnly = [[dateString componentsSeparatedByString:@" "] firstObject];
    }

    // === format it ===
    NSDateFormatter *fmt = [[NSDateFormatter alloc] init];
    fmt.dateFormat = @"yyyy-MM-dd";
    NSDate *dateObj = [fmt dateFromString:dateOnly];
    fmt.dateFormat = @"dd/MM/yyyy";

    UILabel *date = [[UILabel alloc] initWithFrame:CGRectMake(12, 8, 200, 16)];
    date.text = dateObj ? [fmt stringFromDate:dateObj] : @"--/--/----";
    date.textColor = [UIColor grayColor];
    date.font = [UIFont systemFontOfSize:13];
    [card addSubview:date];

    // === 2. Title ===
    UILabel *title = [[UILabel alloc] initWithFrame:CGRectMake(12, 28, 256, 60)];
    title.text = item[@"title"] ?: @"Untitled announcement";
    title.numberOfLines = 3;
    title.font = [UIFont boldSystemFontOfSize:16];
    title.textColor = [UIColor blackColor];
    [card addSubview:title];

    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleAnnouncementTap:)];
    [card addGestureRecognizer:tap];

    return card;
}

- (UIView *)makeAppointmentCard:(NSDictionary *)item width:(CGFloat)width {
    UIView *card = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 90)];
    card.backgroundColor = UIColor.whiteColor;
    card.layer.cornerRadius = 8;
    card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
    card.layer.shadowOpacity = 0.3;
    card.layer.shadowOffset = CGSizeMake(0, 1);

    // Extract fields
    NSString *appointmentType = item[@"appointment_type"] ?: @"-";
    NSString *status = item[@"status"] ?: @"-";
    NSString *startDate = item[@"start_date"] ?: @"-";
    NSString *startTime = item[@"start_time"] ?: @"-";

    NSString *buyerName = @"-";
    NSArray *buyers = item[@"primary_buyer"];
    if ([buyers isKindOfClass:[NSArray class]] && buyers.count > 0) {
        NSDictionary *buyer = buyers.firstObject;
        if ([buyer[@"name"] isKindOfClass:[NSString class]]) {
            buyerName = buyer[@"name"];
        }
    }

    // Notification Icon
    UIView *iconCircle = [[UIView alloc] initWithFrame:CGRectMake(12, 14, 24, 24)];
    iconCircle.backgroundColor = [UIColor colorWithRed:1.0 green:0.4 blue:0.4 alpha:1.0];
    iconCircle.layer.cornerRadius = 12;

    UIImageView *bell = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"bell.fill"]];
    bell.tintColor = UIColor.whiteColor;
    bell.frame = CGRectMake(4, 4, 16, 16);
    [iconCircle addSubview:bell];
    [card addSubview:iconCircle];

    // Status
    UILabel *statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(44, 12, 180, 26)];
    statusLabel.text = status;
    statusLabel.font = [UIFont boldSystemFontOfSize:17];
    statusLabel.textColor = [UIColor colorWithRed:0.0 green:0.43 blue:0.55 alpha:1.0];
    [card addSubview:statusLabel];

    // Time
    UILabel *timeLabel = [[UILabel alloc] initWithFrame:CGRectMake(width - 90, 12, 80, 26)];
    timeLabel.textAlignment = NSTextAlignmentRight;
    timeLabel.text = startTime;
    timeLabel.font = [UIFont boldSystemFontOfSize:15];
    timeLabel.textColor = [UIColor grayColor];
    [card addSubview:timeLabel];

    // Description
    NSString *desc = [NSString stringWithFormat:@"You have a %@ appointment on %@, %@", appointmentType, startDate, buyerName];

    UILabel *descLabel = [[UILabel alloc] initWithFrame:CGRectMake(16, 46, width - 32, 36)];
    descLabel.text = desc;
    descLabel.font = [UIFont systemFontOfSize:15];
    descLabel.numberOfLines = 2;
    descLabel.textColor = [UIColor blackColor];
    [card addSubview:descLabel];

    // Store appointment data so tap handler can retrieve it
    objc_setAssociatedObject(card, "appointmentData", item, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    // Tap
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleAppointmentTap:)];
    [card addGestureRecognizer:tap];

    return card;
}

- (UIView *)makeIssueCard:(NSDictionary *)item width:(CGFloat)width {
    UIView *card = [[UIView alloc] initWithFrame:CGRectMake(0, 0, width, 110)];
    card.backgroundColor = UIColor.whiteColor;
    card.layer.cornerRadius = 8;
    card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
    card.layer.shadowOpacity = 0.3;
    card.layer.shadowOffset = CGSizeMake(0, 1);
    card.layer.masksToBounds = NO;

    // === Extract fields ===
    NSString *status = item[@"status_external"] ?: @"";
    NSString *issueRef = item[@"issue_reference"] ?: @"";
    NSString *createdAt = item[@"created_at"] ?: @"";
    NSString *formattedDate = [self formatDate:createdAt];
    UIColor *statusColor = [self colorForStatus:status];

    // === Determine issue image (like renderOnlineImage) ===
    NSString *issueImage = item[@"image"];
    if (!issueImage || [issueImage isEqualToString:@""]) {
        NSArray *firstArray = item[@"first"];
        NSArray *lastArray = item[@"last"];
        if (firstArray.count > 0 && firstArray[0][@"image"])
            issueImage = firstArray[0][@"image"];
        else if (lastArray.count > 0 && lastArray[0][@"image"])
            issueImage = lastArray[0][@"image"];
    }

    // === Top row: Status + Date ===
    CGFloat iconSize = 16;
    UIView *statusDot = [[UIView alloc] initWithFrame:CGRectMake(12, 12, iconSize, iconSize)];
    statusDot.layer.cornerRadius = iconSize / 2;
    statusDot.backgroundColor = statusColor;
    [card addSubview:statusDot];

    UILabel *statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(CGRectGetMaxX(statusDot.frame) + 6, 8, width - 160, 22)];
    statusLabel.text = status.length ? status : @"Unknown";
    statusLabel.textColor = statusColor;
    statusLabel.font = [UIFont boldSystemFontOfSize:15];
    [card addSubview:statusLabel];

    UILabel *dateLabel = [[UILabel alloc] initWithFrame:CGRectMake(width - 130, 10, 118, 18)];
    dateLabel.textAlignment = NSTextAlignmentRight;
    dateLabel.text = formattedDate;
    dateLabel.textColor = [UIColor grayColor];
    dateLabel.font = [UIFont systemFontOfSize:13];
    [card addSubview:dateLabel];

    // === Divider line ===
//    UIView *divider = [[UIView alloc] initWithFrame:CGRectMake(12, 36, width - 24, 0.5)];
//    divider.backgroundColor = [UIColor colorWithWhite:0.9 alpha:1];
//    [card addSubview:divider];

    // === Image + Info Row ===
    CGFloat imageSize = 44;
    UIImageView *thumbView = [[UIImageView alloc] initWithFrame:CGRectMake(12, 48, imageSize, imageSize)];
    thumbView.layer.cornerRadius = 6;
    thumbView.clipsToBounds = YES;
    thumbView.contentMode = UIViewContentModeScaleAspectFill;

    if (issueImage && issueImage.length > 0) {
        NSURL *url = [NSURL URLWithString:issueImage];
        NSData *data = [NSData dataWithContentsOfURL:url];
        if (data) {
            thumbView.image = [UIImage imageWithData:data];
        } else {
            thumbView.image = [UIImage imageNamed:@"small_placeholder"];
        }
    } else {
        thumbView.image = [UIImage imageNamed:@"small_placeholder"];
    }

    [card addSubview:thumbView];

    // === Text beside image ===
    CGFloat textX = CGRectGetMaxX(thumbView.frame) + 10;
    UILabel *infoLabel = [[UILabel alloc] initWithFrame:CGRectMake(textX, 46, width - textX - 12, 50)];
    infoLabel.numberOfLines = 3;
    infoLabel.textColor = [UIColor blackColor];
    infoLabel.font = [UIFont systemFontOfSize:15];

    infoLabel.attributedText = [self notificationTextForIssue:item];

    [card addSubview:infoLabel];
  
    // Keep a reference to its issue data
    card.accessibilityValue = item[@"issue_reference"]; // for debugging
    card.tag = self.issues.count; // optional index tagging

    // Store the data for later use (simplest way)
    objc_setAssociatedObject(card, "issueData", item, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

    // === Tap gesture ===
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleIssueTap:)];
    [card addGestureRecognizer:tap];

    return card;
}

// Convert hex string (like "#F14915") to UIColor
- (UIColor *)colorFromHex:(NSString *)hexString {
    unsigned rgbValue = 0;
    NSScanner *scanner = [NSScanner scannerWithString:hexString];
    [scanner setScanLocation:1];
    [scanner scanHexInt:&rgbValue];
    return [UIColor colorWithRed:((rgbValue & 0xFF0000) >> 16) / 255.0
                           green:((rgbValue & 0x00FF00) >> 8) / 255.0
                            blue:(rgbValue & 0x0000FF) / 255.0
                           alpha:1.0];
}

// Status → Color
- (UIColor *)colorForStatus:(NSString *)status {
    if ([status isEqualToString:@"Lodged"]) return [self colorFromHex:@"#2952D6"];
    if ([status isEqualToString:@"New"]) return [self colorFromHex:@"#F99100"];
    if ([status isEqualToString:@"Pending Start"]) return [self colorFromHex:@"#BD5607"];
    if ([status isEqualToString:@"Withdraw"] || [status isEqualToString:@"WITHDRAW"] || [status isEqualToString:@"VOID"])
        return [self colorFromHex:@"#EFC089"];
    if ([status isEqualToString:@"WIP"] || [status isEqualToString:@"W.I.P"])
        return [self colorFromHex:@"#F6C607"];
    if ([status isEqualToString:@"Completed"]) return [self colorFromHex:@"#DF00D0"];
    if ([status isEqualToString:@"Pending Access"]) return [self colorFromHex:@"#F14915"];
    if ([status isEqualToString:@"Pending Owner Acceptance"]) return [self colorFromHex:@"#EF7215"];
    if ([status isEqualToString:@"Rejected"]) return [self colorFromHex:@"#FF3939"];
    if ([status isEqualToString:@"Close Internal"]) return [self colorFromHex:@"#58BA63"];
    if ([status isEqualToString:@"Close External"]) return [self colorFromHex:@"#1C7C00"];
    return [UIColor darkGrayColor];
}

- (NSAttributedString *)notificationTextForIssue:(NSDictionary *)issue {
    NSString *status = issue[@"status_external"] ?: @"";
    NSString *issueRef = issue[@"issue_reference"] ?: @"";
    NSString *projectName = self.projectName; // Replace with GLOBALS.PROJECT_NAME if available

    // Base sentence builder
    NSString *text = @"";
    if ([status isEqualToString:@"New"]) {
        text = [NSString stringWithFormat:@"New issue %@ from %@ has been created.", issueRef, projectName];
    } else if ([status isEqualToString:@"Lodged"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has been lodged.", issueRef, projectName];
    } else if ([status isEqualToString:@"Pending Start"]) {
        text = [NSString stringWithFormat:@"%@ from %@ is pending start.", issueRef, projectName];
    } else if ([status isEqualToString:@"Pending Access"]) {
        text = [NSString stringWithFormat:@"%@ from %@ is pending access.", issueRef, projectName];
    } else if ([status isEqualToString:@"W.I.P"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has changed status to W.I.P.", issueRef, projectName];
    } else if ([status isEqualToString:@"Not Me"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has changed status to Not Me.", issueRef, projectName];
    } else if ([status isEqualToString:@"Reassign"]) {
        text = [NSString stringWithFormat:@"%@ from %@ needs to be reassigned.", issueRef, projectName];
    } else if ([status isEqualToString:@"Completed"]) {
        text = [NSString stringWithFormat:@"%@ from %@ is completed.", issueRef, projectName];
    } else if ([status isEqualToString:@"Redo"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has changed status to Redo.", issueRef, projectName];
    } else if ([status isEqualToString:@"Close Internal"]) {
        text = [NSString stringWithFormat:@"%@ from %@ is closed internally.", issueRef, projectName];
    } else if ([status isEqualToString:@"Close External"]) {
        text = [NSString stringWithFormat:@"%@ from %@ is closed externally.", issueRef, projectName];
    } else if ([status isEqualToString:@"Rejected"] ||
               [status isEqualToString:@"Decline"] ||
               [status isEqualToString:@"Withdraw"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has changed status to %@.", issueRef, projectName, status];
    } else if ([status isEqualToString:@"Pending Owner Acceptance"] ||
               [status isEqualToString:@"POA"] ||
               [status isEqualToString:@"poa"]) {
        text = [NSString stringWithFormat:@"%@ from %@ has changed status to Pending Owner Acceptance.", issueRef, projectName];
    } else {
        text = [NSString stringWithFormat:@"Issue %@ (%@)", issueRef, status];
    }

    // === Create the base attributed string ===
    NSMutableAttributedString *attrText = [[NSMutableAttributedString alloc] initWithString:text
                                                                                 attributes:@{
        NSFontAttributeName: [UIFont systemFontOfSize:15],
        NSForegroundColorAttributeName: UIColor.blackColor
    }];

    // === Highlight the status substring ===
    UIColor *statusColor = [self colorForStatus:status];
    NSRange statusRange = [text rangeOfString:status options:NSCaseInsensitiveSearch];
    if (statusRange.location != NSNotFound) {
        [attrText addAttributes:@{
            NSFontAttributeName: [UIFont boldSystemFontOfSize:15],
            NSForegroundColorAttributeName: statusColor
        } range:statusRange];
    }

    return attrText;
}

- (NSString *)formatDate:(NSString *)inputDateString {
    if (!inputDateString || inputDateString.length == 0) return @"--/--/----";
    NSDateFormatter *inputFmt = [[NSDateFormatter alloc] init];
    inputFmt.dateFormat = @"yyyy-MM-dd HH:mm:ss";
    NSDate *date = [inputFmt dateFromString:inputDateString];
    if (!date) return inputDateString;
    NSDateFormatter *outputFmt = [[NSDateFormatter alloc] init];
    outputFmt.dateFormat = @"dd/MM/yyyy";
    return [outputFmt stringFromDate:date];
}

#pragma mark - Individual Card Taps
- (void)handleAnnouncementTap:(UITapGestureRecognizer *)gesture {
    UIView *card = gesture.view;
    [self animateTapForView:card];
    NSLog(@"📰 Announcement card tapped");
    // TODO: open AnnouncementDetailsScreen equivalent in future
}

- (void)handleAppointmentTap:(UITapGestureRecognizer *)gesture {
    UIView *card = gesture.view;
    [self animateTapForView:card];

    NSDictionary *appointmentData = objc_getAssociatedObject(card, "appointmentData");

    if (!appointmentData) {
        NSLog(@"⚠️ No appointment data found");
        return;
    }

    NSLog(@"📅 Opening AppointmentDetails with: %@", appointmentData);

    AppointmentDetailsViewController *vc = [[AppointmentDetailsViewController alloc] init];
    vc.modalPresentationStyle = UIModalPresentationFullScreen;
    vc.appointmentData = appointmentData;
    [self presentViewController:vc animated:YES completion:nil];
}


- (void)handleIssueTap:(UITapGestureRecognizer *)gesture {
    UIView *tappedCard = gesture.view;
    NSDictionary *issueData = objc_getAssociatedObject(tappedCard, "issueData");

    if (issueData && [issueData isKindOfClass:[NSDictionary class]]) {
        NSLog(@"🧭 Navigating to IssueDetailViewController with issue: %@", issueData);

        IssueDetailViewController *nextVC = [[IssueDetailViewController alloc] init];
        nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
        nextVC.issueData = issueData;
        [self presentViewController:nextVC animated:YES completion:nil];
    } else {
        NSLog(@"⚠️ No valid issue data found for tapped card: %@", issueData);
    }
}

- (UIImage *)downloadImageFrom:(NSString *)urlString {
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
    return data ? [UIImage imageWithData:data] : [UIImage imageNamed:@"header_bg"];
}

#pragma mark - Card Factory with Tap Animation
- (UIView *)createCardWithText:(NSString *)text frame:(CGRect)frame {
    UIView *card = [[UIView alloc] initWithFrame:frame];
    card.backgroundColor = [UIColor whiteColor];
    card.layer.cornerRadius = 8;
    card.layer.shadowColor = [UIColor colorWithWhite:0 alpha:0.1].CGColor;
    card.layer.shadowOpacity = 0.8;
    card.layer.shadowOffset = CGSizeMake(0, 1);
    card.userInteractionEnabled = YES;

    UILabel *body = [[UILabel alloc] initWithFrame:CGRectMake(12, 12, frame.size.width - 24, frame.size.height - 24)];
    body.text = text;
    body.numberOfLines = 2;
    body.font = [UIFont systemFontOfSize:15];
    [card addSubview:body];

    // Add tap gesture with animation
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(cardTapped:)];
    [card addGestureRecognizer:tap];

    return card;
}

#pragma mark - Tap Handlers
- (void)sectionHeaderTapped:(UITapGestureRecognizer *)gesture {
    UILabel *header = (UILabel *)gesture.view;
    [self animateTapForView:header];
    NSLog(@"📘 Section tapped: %@", header.text);
}

-(void)issueHeaderTapped:(UITapGestureRecognizer *)gesture {
    IssuesViewController *nextVC = [[IssuesViewController alloc] init];
    nextVC.modalPresentationStyle = UIModalPresentationFullScreen;
    [self presentViewController:nextVC animated:YES completion:nil];
}


- (void)cardTapped:(UITapGestureRecognizer *)gesture {
    UIView *card = gesture.view;
    [self animateTapForView:card];
    NSLog(@"🟩 Card tapped: %@", ((UILabel *)card.subviews.firstObject).text);
}

- (void)animateTapForView:(UIView *)view {
    [UIView animateWithDuration:0.1 animations:^{
        view.transform = CGAffineTransformMakeScale(0.96, 0.96);
        view.alpha = 0.8;
    } completion:^(BOOL finished) {
        [UIView animateWithDuration:0.1 animations:^{
            view.transform = CGAffineTransformIdentity;
            view.alpha = 1.0;
        }];
    }];
}

#pragma mark - Loading Overlay
- (void)showLoadingOverlay:(NSString *)message {
    if (self.loadingOverlay.superview) return; // already showing

    UIView *overlay = [[UIView alloc] initWithFrame:self.view.bounds];
    overlay.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4];
    overlay.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;

    UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
                                        initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
    spinner.center = overlay.center;
    spinner.color = UIColor.whiteColor;
    [spinner startAnimating];

    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, CGRectGetMaxY(spinner.frame) + 16,
                                                               overlay.bounds.size.width, 30)];
    label.text = message ?: @"Loading...";
    label.textAlignment = NSTextAlignmentCenter;
    label.textColor = UIColor.whiteColor;
    label.font = [UIFont boldSystemFontOfSize:16];

    [overlay addSubview:spinner];
    [overlay addSubview:label];
    [self.view addSubview:overlay];

    self.loadingOverlay = overlay;
    self.spinner = spinner;
}

- (void)hideLoadingOverlay {
    [self.spinner stopAnimating];
    [self.loadingOverlay removeFromSuperview];
    self.loadingOverlay = nil;
    self.spinner = nil;
}

@end
