// SyncProjectViewController.mm
#import "SyncProjectViewController.h"
#import "LocalStorage.h"
#import "APIClient.h"
#import "NetworkManager.h"
#import "OfflineSyncManager.h"

typedef NS_ENUM(NSInteger, SyncProjectScreenState) {
    SyncProjectScreenStateOfflineUnit,
    SyncProjectScreenStateSelectProject,
    SyncProjectScreenStateSelectUnit
};

static NSString * const kSyncSelectedUnitsKey = @"SYNC_SELECTEDUNITS";
static NSString * const kProjectListKey = @"PROJECT_LIST";

@interface SyncUnit : NSObject <NSSecureCoding>
@property (nonatomic, strong) NSString *planId;
@property (nonatomic, strong) NSString *displayName;
@property (nonatomic, strong) NSDictionary *project;
@property (nonatomic, strong) NSString *projectId;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, assign) BOOL selected;
@end

@implementation SyncUnit

+ (BOOL)supportsSecureCoding {
    return YES;
}

- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.planId forKey:@"planId"];
    [coder encodeObject:self.displayName forKey:@"displayName"];
    [coder encodeObject:self.project forKey:@"project"];
    [coder encodeObject:self.projectId forKey:@"projectId"];
    [coder encodeObject:self.projectName forKey:@"projectName"];
    [coder encodeBool:self.selected forKey:@"selected"];
}

- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        _planId = [coder decodeObjectOfClass:[NSString class] forKey:@"planId"];
        _displayName = [coder decodeObjectOfClass:[NSString class] forKey:@"displayName"];
        _project = [coder decodeObjectOfClass:[NSDictionary class] forKey:@"project"];
        _projectId = [coder decodeObjectOfClass:[NSString class] forKey:@"projectId"];
        _projectName = [coder decodeObjectOfClass:[NSString class] forKey:@"projectName"];
        _selected = [coder decodeBoolForKey:@"selected"];
    }
    return self;
}

@end

@interface SyncProject : NSObject
@property (nonatomic, strong) NSString *projectId;
@property (nonatomic, strong) NSString *projectName;
@property (nonatomic, strong) NSString *projectLogo;
@property (nonatomic, strong) NSArray<SyncUnit *> *units;
@end

@implementation SyncProject
@end

@interface SyncUnitTableViewCell : UITableViewCell

@property (nonatomic, strong) UILabel *unitLabel;
@property (nonatomic, strong) UIButton *checkboxButton;
@property (nonatomic, strong) SyncUnit *unit;

- (void)configureWithUnit:(SyncUnit *)unit;

@end

@implementation SyncUnitTableViewCell

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier {

    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {

        self.backgroundColor = UIColor.clearColor; // transparent background for spacing
        self.selectionStyle = UITableViewCellSelectionStyleNone;

        // Container view (card look)
        UIView *bgView = [[UIView alloc] init];
        bgView.backgroundColor = UIColor.whiteColor;
        bgView.layer.cornerRadius = 8;
        bgView.layer.masksToBounds = YES;
        bgView.layer.borderColor = [UIColor lightGrayColor].CGColor;
        bgView.layer.borderWidth = 1.0;
        bgView.translatesAutoresizingMaskIntoConstraints = NO;
        [self.contentView addSubview:bgView];

        // Unit label
        self.unitLabel = [[UILabel alloc] init];
        self.unitLabel.font = [UIFont systemFontOfSize:16];
        self.unitLabel.translatesAutoresizingMaskIntoConstraints = NO;
        [bgView addSubview:self.unitLabel];

        // Checkbox button
        self.checkboxButton = [UIButton buttonWithType:UIButtonTypeCustom];
        self.checkboxButton.translatesAutoresizingMaskIntoConstraints = NO;
        [self.checkboxButton addTarget:self
                                action:@selector(onCheckboxTapped)
                      forControlEvents:UIControlEventTouchUpInside];
        [bgView addSubview:self.checkboxButton];

        // Constraints for bgView (spacing from table edges)
        [NSLayoutConstraint activateConstraints:@[
            [bgView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor constant:4],
            [bgView.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-4],
            [bgView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor constant:16],
            [bgView.trailingAnchor constraintEqualToAnchor:self.contentView.trailingAnchor constant:-16],
        ]];

        // Constraints for label and checkbox inside bgView
        [NSLayoutConstraint activateConstraints:@[
            [self.unitLabel.leadingAnchor constraintEqualToAnchor:bgView.leadingAnchor constant:12],
            [self.unitLabel.centerYAnchor constraintEqualToAnchor:bgView.centerYAnchor],
            
            [self.checkboxButton.trailingAnchor constraintEqualToAnchor:bgView.trailingAnchor constant:-12],
            [self.checkboxButton.centerYAnchor constraintEqualToAnchor:bgView.centerYAnchor],
            [self.checkboxButton.widthAnchor constraintEqualToConstant:24],
            [self.checkboxButton.heightAnchor constraintEqualToConstant:24],

            [self.unitLabel.trailingAnchor constraintEqualToAnchor:self.checkboxButton.leadingAnchor constant:-8],
        ]];
    }
    return self;
}

- (void)configureWithUnit:(SyncUnit *)unit {
    self.unit = unit;
    self.unitLabel.text = unit.displayName;

    UIImage *image = unit.selected
        ? [UIImage systemImageNamed:@"checkmark.square.fill"]
        : [UIImage systemImageNamed:@"square"];
    [self.checkboxButton setImage:image forState:UIControlStateNormal];
}

- (void)onCheckboxTapped {
    if (self.unit) {
        self.unit.selected = !self.unit.selected;

        UIImage *image = self.unit.selected
            ? [UIImage systemImageNamed:@"checkmark.square.fill"]
            : [UIImage systemImageNamed:@"square"];
        [self.checkboxButton setImage:image forState:UIControlStateNormal];

        // Notify VC about the change
        [[NSNotificationCenter defaultCenter] postNotificationName:@"SyncUnitCheckboxTapped"
                                                            object:self.unit];
    }
}

@end

@interface SyncProjectViewController ()
<
UITableViewDelegate,
UITableViewDataSource,
UICollectionViewDelegate,
UICollectionViewDataSource
>

// Header
@property (nonatomic, strong) UIView *headerView;
@property (nonatomic, strong) UIButton *backButton;
@property (nonatomic, strong) UILabel *titleLabel;

// Content containers
@property (nonatomic, strong) UIView *offlineUnitView;
@property (nonatomic, strong) UIView *selectProjectView;
@property (nonatomic, strong) UIView *selectUnitView;

// Common UI
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIActivityIndicatorView *loadingView;

// State
@property (nonatomic, assign) NSInteger selectedUnitCount;

@property (nonatomic, assign) SyncProjectScreenState screenState;
@property (nonatomic, assign) BOOL hasChanges;
@property (nonatomic, strong) NSMutableArray<SyncUnit *> *selectedUnits;

@property (nonatomic, strong) UITableView *offlineTableView;
@property (nonatomic, strong) UITableView *unitTableView;
@property (nonatomic, strong) UICollectionView *projectCollectionView;
@property (nonatomic, strong) UILabel *offlineUnitCountLabel;

@property (nonatomic, strong) NSMutableArray<SyncProject *> *projects;
@property (nonatomic, assign) BOOL isLoadingProjects;
@property (nonatomic, strong) SyncProject *currentProject;

@property (nonatomic, strong) NSDictionary<NSString *, NSArray<SyncUnit *> *> *selectedUnitsByProject;
@property (nonatomic, strong) NSArray<NSString *> *projectNamesSorted;

@property (nonatomic, strong) UILabel *selectProjectUnitCountLabel;

@end


@implementation SyncProjectViewController
- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor colorWithWhite:0.96 alpha:1.0];

    self.projects = [NSMutableArray array];
    self.selectedUnits = [NSMutableArray array];
  
    self.loadingView =
        [[UIActivityIndicatorView alloc]
         initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge];
    self.loadingView.center = self.view.center;
    self.loadingView.hidesWhenStopped = YES;
    [self.view addSubview:self.loadingView];


    [self loadSelectedUnits];
    [self loadProjectList];
    
    [self setupHeader];
    [self setupContentContainers];
    [self setupOfflineUnitView];
    [self setupSelectProjectView];
    [self setupSelectUnitView];

    [self setScreenState:SyncProjectScreenStateOfflineUnit];
  
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(onUnitCheckboxChanged:)
                                                 name:@"SyncUnitCheckboxTapped"
                                               object:nil];
}

#pragma mark - Header
- (void)setupHeader {
    self.headerView = [[UIView alloc] init];
    self.headerView.backgroundColor = [UIColor colorWithRed:0.0 green:0.5 blue:0.6 alpha:1.0];
    self.headerView.translatesAutoresizingMaskIntoConstraints = NO;
    [self.view addSubview:self.headerView];
    self.backButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [self.backButton setImage:[UIImage systemImageNamed:@"chevron.backward"] forState:UIControlStateNormal];
    [self.backButton addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside];
    self.backButton.translatesAutoresizingMaskIntoConstraints = NO;
    self.backButton.tintColor = UIColor.whiteColor;
    [self.headerView addSubview:self.backButton];
    self.titleLabel = [[UILabel alloc] init];
    self.titleLabel.text = @"Offline Unit";
    self.titleLabel.textColor = UIColor.whiteColor;
    self.titleLabel.font = [UIFont boldSystemFontOfSize:18];
    self.titleLabel.translatesAutoresizingMaskIntoConstraints = NO;
    [self.headerView addSubview:self.titleLabel];
    
    // Constraints
    [NSLayoutConstraint activateConstraints:@[
        [self.headerView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor],
        [self.headerView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
        [self.headerView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
        [self.headerView.heightAnchor constraintEqualToConstant:48],
        [self.backButton.leadingAnchor constraintEqualToAnchor:self.headerView.leadingAnchor constant:8],
        [self.backButton.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
        [self.backButton.widthAnchor constraintEqualToConstant:32],
        [self.backButton.heightAnchor constraintEqualToConstant:32],
        [self.titleLabel.centerXAnchor constraintEqualToAnchor:self.headerView.centerXAnchor],
        [self.titleLabel.centerYAnchor constraintEqualToAnchor:self.headerView.centerYAnchor],
    ]];
}

- (void)setHeaderTitle:(NSString *)title {
    self.titleLabel.text = title;
}

#pragma mark - Setup ContentContainer
- (void)setupContentContainers {
    self.offlineUnitView = [UIView new];
    self.selectProjectView = [UIView new];
    self.selectUnitView = [UIView new];

    NSArray *views = @[self.offlineUnitView, self.selectProjectView, self.selectUnitView];

    for (UIView *v in views) {
        v.translatesAutoresizingMaskIntoConstraints = NO;
        v.hidden = YES;
        [self.view addSubview:v];

        [NSLayoutConstraint activateConstraints:@[
            [v.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor],
            [v.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor],
            [v.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor],
            [v.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor],
        ]];
    }
}

#pragma mark - Offline Unit View
- (void)setupOfflineUnitView {
    self.offlineUnitCountLabel = [UILabel new];
    self.offlineUnitCountLabel.font = [UIFont boldSystemFontOfSize:24];
    self.offlineUnitCountLabel.text = @"No Units Selected";
    self.offlineUnitCountLabel.translatesAutoresizingMaskIntoConstraints = NO;

    UIButton *addButton = [UIButton buttonWithType:UIButtonTypeCustom];
    [addButton setImage:[UIImage systemImageNamed:@"plus"]
               forState:UIControlStateNormal];
    addButton.tintColor = [UIColor systemTealColor];
    addButton.translatesAutoresizingMaskIntoConstraints = NO;
    [addButton addTarget:self
                  action:@selector(onAddUnit)
        forControlEvents:UIControlEventTouchUpInside];

    UILabel *infoLabel = [UILabel new];
    infoLabel.text = @"Maximum of 10 units can be listed only.\nPlease remove existing units in the listing to add a new one.";
    infoLabel.font = [UIFont systemFontOfSize:16];
    infoLabel.numberOfLines = 0;
    infoLabel.lineBreakMode = NSLineBreakByWordWrapping;
    infoLabel.translatesAutoresizingMaskIntoConstraints = NO;

    self.offlineTableView =
        [[UITableView alloc] initWithFrame:CGRectZero
                                     style:UITableViewStylePlain]; // <- plain style
    self.offlineTableView.translatesAutoresizingMaskIntoConstraints = NO;
    self.offlineTableView.delegate = self;
    self.offlineTableView.dataSource = self;
    self.offlineTableView.allowsSelection = NO;
    self.offlineTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
    [self.offlineTableView registerClass:UITableViewCell.class
                  forCellReuseIdentifier:@"OfflineUnitCell"];
    self.offlineTableView.backgroundColor = UIColor.clearColor; // table bg shows

    [self.offlineUnitView addSubview:self.offlineUnitCountLabel];
    [self.offlineUnitView addSubview:addButton];
    [self.offlineUnitView addSubview:infoLabel];
    [self.offlineUnitView addSubview:self.offlineTableView];

    [NSLayoutConstraint activateConstraints:@[
        [self.offlineUnitCountLabel.topAnchor constraintEqualToAnchor:self.offlineUnitView.topAnchor constant:16],
        [self.offlineUnitCountLabel.leadingAnchor constraintEqualToAnchor:self.offlineUnitView.leadingAnchor constant:16],

        [addButton.trailingAnchor constraintEqualToAnchor:self.offlineUnitView.trailingAnchor constant:-16],
        [addButton.centerYAnchor constraintEqualToAnchor:self.offlineUnitCountLabel.centerYAnchor],
        [addButton.widthAnchor constraintEqualToConstant:24],
        [addButton.heightAnchor constraintEqualToConstant:24],

        [infoLabel.topAnchor constraintEqualToAnchor:self.offlineUnitCountLabel.bottomAnchor constant:12],
        [infoLabel.leadingAnchor constraintEqualToAnchor:self.offlineUnitCountLabel.leadingAnchor],
        [infoLabel.trailingAnchor constraintEqualToAnchor:self.offlineUnitView.trailingAnchor constant:-16],

        [self.offlineTableView.topAnchor constraintEqualToAnchor:infoLabel.bottomAnchor constant:12],
       [self.offlineTableView.leadingAnchor constraintEqualToAnchor:self.offlineUnitView.leadingAnchor],
       [self.offlineTableView.trailingAnchor constraintEqualToAnchor:self.offlineUnitView.trailingAnchor],
       [self.offlineTableView.bottomAnchor constraintEqualToAnchor:self.offlineUnitView.bottomAnchor],
    ]];
}

#pragma mark - Select Project View
- (void)setupSelectProjectView {
    self.selectProjectUnitCountLabel = [UILabel new];
    self.selectProjectUnitCountLabel.font = [UIFont boldSystemFontOfSize:24];
    self.selectProjectUnitCountLabel.translatesAutoresizingMaskIntoConstraints = NO;

    // Set initial text based on selectedUnits count
    [self updateSelectProjectUnitCountLabel];

    UILabel *instructionLabel = [UILabel new];
    instructionLabel.text = @"Please select a project";
    instructionLabel.font = [UIFont systemFontOfSize:18];
    instructionLabel.translatesAutoresizingMaskIntoConstraints = NO;

    UISearchBar *searchBar = [UISearchBar new];
    searchBar.translatesAutoresizingMaskIntoConstraints = NO;

    UICollectionViewFlowLayout *layout = [UICollectionViewFlowLayout new];
    layout.itemSize = CGSizeMake(self.view.bounds.size.width - 32, 140);
    layout.minimumLineSpacing = 12;

    self.projectCollectionView =
        [[UICollectionView alloc] initWithFrame:CGRectZero
                           collectionViewLayout:layout];
    self.projectCollectionView.translatesAutoresizingMaskIntoConstraints = NO;
    self.projectCollectionView.backgroundColor = UIColor.clearColor;
    self.projectCollectionView.delegate = self;
    self.projectCollectionView.dataSource = self;
    [self.projectCollectionView registerClass:UICollectionViewCell.class
                   forCellWithReuseIdentifier:@"ProjectCell"];

    [self.selectProjectView addSubview:instructionLabel];
    [self.selectProjectView addSubview:self.selectProjectUnitCountLabel];
    [self.selectProjectView addSubview:searchBar];
    [self.selectProjectView addSubview:self.projectCollectionView];

    [NSLayoutConstraint activateConstraints:@[
      [self.selectProjectUnitCountLabel.topAnchor constraintEqualToAnchor:self.selectProjectView.topAnchor constant:16],
      [self.selectProjectUnitCountLabel.leadingAnchor constraintEqualToAnchor:self.selectProjectView.leadingAnchor constant:16],

        [instructionLabel.topAnchor constraintEqualToAnchor:self.selectProjectUnitCountLabel.bottomAnchor constant:8],
        [instructionLabel.leadingAnchor constraintEqualToAnchor:self.selectProjectUnitCountLabel.leadingAnchor],

        [searchBar.topAnchor constraintEqualToAnchor:instructionLabel.bottomAnchor constant:8],
        [searchBar.leadingAnchor constraintEqualToAnchor:self.selectProjectView.leadingAnchor],
        [searchBar.trailingAnchor constraintEqualToAnchor:self.selectProjectView.trailingAnchor],

        [self.projectCollectionView.topAnchor constraintEqualToAnchor:searchBar.bottomAnchor constant:8],
        [self.projectCollectionView.leadingAnchor constraintEqualToAnchor:self.selectProjectView.leadingAnchor],
        [self.projectCollectionView.trailingAnchor constraintEqualToAnchor:self.selectProjectView.trailingAnchor],
        [self.projectCollectionView.bottomAnchor constraintEqualToAnchor:self.selectProjectView.bottomAnchor],
    ]];
}

#pragma mark - Select Unit View
- (void)setupSelectUnitView {
    self.selectProjectUnitCountLabel = [UILabel new];
    self.selectProjectUnitCountLabel.font = [UIFont boldSystemFontOfSize:24];
    self.selectProjectUnitCountLabel.translatesAutoresizingMaskIntoConstraints = NO;

    // Set initial text based on selectedUnits count
    [self updateSelectProjectUnitCountLabel];

    UILabel *instructionLabel = [UILabel new];
    instructionLabel.text = @"Please select a unit";
    instructionLabel.translatesAutoresizingMaskIntoConstraints = NO;

    UISearchBar *searchBar = [UISearchBar new];
    searchBar.translatesAutoresizingMaskIntoConstraints = NO;

    self.unitTableView = [[UITableView alloc] initWithFrame:CGRectZero
                                                      style:UITableViewStylePlain];
    self.unitTableView.translatesAutoresizingMaskIntoConstraints = NO;
    self.unitTableView.delegate = self;
    self.unitTableView.dataSource = self;
    self.unitTableView.separatorStyle = UITableViewCellSeparatorStyleNone; // Remove lines
    self.unitTableView.backgroundColor = UIColor.clearColor; // Matches screen background
    self.unitTableView.showsVerticalScrollIndicator = NO;
    self.unitTableView.sectionHeaderHeight = 0.0;
    self.unitTableView.estimatedSectionHeaderHeight = 0.0;
    [self.unitTableView registerClass:SyncUnitTableViewCell.class
                 forCellReuseIdentifier:@"UnitCell"];

    UIButton *doneButton = [UIButton buttonWithType:UIButtonTypeSystem];
    [doneButton setTitle:@"Done" forState:UIControlStateNormal];
    doneButton.backgroundColor = [UIColor systemTealColor];
    doneButton.tintColor = UIColor.whiteColor;
    doneButton.layer.cornerRadius = 8;
    doneButton.translatesAutoresizingMaskIntoConstraints = NO;
    [doneButton addTarget:self
                   action:@selector(onDone)
         forControlEvents:UIControlEventTouchUpInside];

    [self.selectUnitView addSubview:self.selectProjectUnitCountLabel];
    [self.selectUnitView addSubview:instructionLabel];
    [self.selectUnitView addSubview:searchBar];
    [self.selectUnitView addSubview:self.unitTableView];
    [self.selectUnitView addSubview:doneButton];

    [NSLayoutConstraint activateConstraints:@[
        [self.selectProjectUnitCountLabel.topAnchor constraintEqualToAnchor:self.selectUnitView.topAnchor constant:16],
        [self.selectProjectUnitCountLabel.leadingAnchor constraintEqualToAnchor:self.selectUnitView.leadingAnchor constant:16],

        [instructionLabel.topAnchor constraintEqualToAnchor:self.selectProjectUnitCountLabel.bottomAnchor constant:8],
        [instructionLabel.leadingAnchor constraintEqualToAnchor:self.selectProjectUnitCountLabel.leadingAnchor],

        [searchBar.topAnchor constraintEqualToAnchor:instructionLabel.bottomAnchor constant:8],
        [searchBar.leadingAnchor constraintEqualToAnchor:self.selectUnitView.leadingAnchor],
        [searchBar.trailingAnchor constraintEqualToAnchor:self.selectUnitView.trailingAnchor],

        [self.unitTableView.topAnchor constraintEqualToAnchor:searchBar.bottomAnchor constant:8],
        [self.unitTableView.leadingAnchor constraintEqualToAnchor:self.selectUnitView.leadingAnchor],
        [self.unitTableView.trailingAnchor constraintEqualToAnchor:self.selectUnitView.trailingAnchor],

        [doneButton.topAnchor constraintEqualToAnchor:self.unitTableView.bottomAnchor constant:12],
        [doneButton.leadingAnchor constraintEqualToAnchor:self.selectUnitView.leadingAnchor constant:16],
        [doneButton.trailingAnchor constraintEqualToAnchor:self.selectUnitView.trailingAnchor constant:-16],
        [doneButton.heightAnchor constraintEqualToConstant:48],
        [doneButton.bottomAnchor constraintEqualToAnchor:self.selectUnitView.safeAreaLayoutGuide.bottomAnchor],
    ]];
}

#pragma mark - UITableViewDataSource
- (UITableViewCell *)tableView:(UITableView *)tableView
         cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (tableView == self.offlineTableView) {

        UITableViewCell *cell =
            [tableView dequeueReusableCellWithIdentifier:@"OfflineUnitCell"
                                            forIndexPath:indexPath];

        cell.selectionStyle = UITableViewCellSelectionStyleNone;
        cell.backgroundColor = UIColor.clearColor;

        for (UIView *v in cell.contentView.subviews) {
            [v removeFromSuperview];
        }

        NSString *projectName = self.projectNamesSorted[indexPath.section];
        NSArray<SyncUnit *> *units = self.selectedUnitsByProject[projectName];

        if (indexPath.row >= units.count) {
            return cell;
        }

        SyncUnit *unit = units[indexPath.row];

        // ---- Card container ----
        UIView *bgView = [[UIView alloc] init];
        bgView.backgroundColor = UIColor.whiteColor;
        bgView.layer.cornerRadius = 8;
        bgView.layer.borderWidth = 1;
        bgView.layer.borderColor = UIColor.lightGrayColor.CGColor;
        bgView.translatesAutoresizingMaskIntoConstraints = NO;
        [cell.contentView addSubview:bgView];

        CGFloat spacing = 6;
        [NSLayoutConstraint activateConstraints:@[
            [bgView.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor constant:spacing],
            [bgView.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor constant:-spacing],
            [bgView.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:16],
            [bgView.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor constant:-16],
        ]];

        UILabel *unitLabel = [[UILabel alloc] init];
        unitLabel.text = unit.displayName;
        unitLabel.translatesAutoresizingMaskIntoConstraints = NO;
        [bgView addSubview:unitLabel];

        UIButton *deleteButton = [UIButton buttonWithType:UIButtonTypeSystem];
        deleteButton.tintColor = [UIColor colorWithRed:0.0 green:0.5 blue:0.6 alpha:1.0];
        [deleteButton setImage:[UIImage systemImageNamed:@"trash"]
                      forState:UIControlStateNormal];
        deleteButton.translatesAutoresizingMaskIntoConstraints = NO;
        [deleteButton addTarget:self
                         action:@selector(onDeleteUnitFromProject:)
               forControlEvents:UIControlEventTouchUpInside];
        [bgView addSubview:deleteButton];

        [NSLayoutConstraint activateConstraints:@[
            [unitLabel.leadingAnchor constraintEqualToAnchor:bgView.leadingAnchor constant:12],
            [unitLabel.centerYAnchor constraintEqualToAnchor:bgView.centerYAnchor],

            [deleteButton.trailingAnchor constraintEqualToAnchor:bgView.trailingAnchor constant:-12],
            [deleteButton.centerYAnchor constraintEqualToAnchor:bgView.centerYAnchor],
            [deleteButton.widthAnchor constraintEqualToConstant:32],
            [deleteButton.heightAnchor constraintEqualToConstant:32],

            [unitLabel.trailingAnchor constraintEqualToAnchor:deleteButton.leadingAnchor constant:-8],
        ]];

        return cell;
    } else if (tableView == self.unitTableView) {
        SyncUnitTableViewCell *cell =
            [tableView dequeueReusableCellWithIdentifier:@"UnitCell"
                                            forIndexPath:indexPath];

        SyncUnit *unit = self.currentProject.units[indexPath.row];
        [cell configureWithUnit:unit];

        return cell;
    }

    // Other tables
    return [tableView dequeueReusableCellWithIdentifier:@"UnitCell"
                                           forIndexPath:indexPath];
}

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    if (tableView == self.offlineTableView) {
        NSLog(@"[TABLE] sections = %lu",
              (unsigned long)self.projectNamesSorted.count);
        return self.projectNamesSorted.count;
    }

    return 1;
}


- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if (tableView == self.offlineTableView) {
        NSString *projectName = self.projectNamesSorted[section];
        NSArray<SyncUnit *> *units = self.selectedUnitsByProject[projectName];
        return units.count;
    } else if (tableView == self.unitTableView) {
        return self.currentProject.units.count;
    }
    return 0;
}

- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section {
    if (tableView == self.offlineTableView) {
        return self.projectNamesSorted[section];
    }
    return nil;
}

- (CGFloat)tableView:(UITableView *)tableView
heightForRowAtIndexPath:(NSIndexPath *)indexPath {

    if (tableView == self.offlineTableView) {
        return 52;
    }

    if (tableView == self.unitTableView) {
        return 52;
    }

    return UITableViewAutomaticDimension;
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section {
    if (tableView == self.offlineTableView) {
        return 44; // increase this number for taller black bar
    }
    return 0;
}

- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section {
    if (tableView == self.unitTableView) {
      return 12; // total height of the cell including spacing
    }
    return UITableViewAutomaticDimension;
}

#pragma mark - UITableViewDelegate
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
  
  SyncUnit *unit;
  if (tableView == self.offlineTableView) {
    return;
  } else {
    unit = self.currentProject.units[indexPath.row];
  }
  
  [self toggleUnit:unit];
  
  [tableView reloadRowsAtIndexPaths:@[indexPath]
                   withRowAnimation:UITableViewRowAnimationNone];
}

- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
    if (tableView != self.offlineTableView) return nil;

    NSString *projectName = self.projectNamesSorted[section];
    UIView *headerView = [[UIView alloc] init];
    headerView.backgroundColor = [UIColor blackColor];

    UILabel *label = [[UILabel alloc] init];
    label.text = projectName;
    label.textColor = UIColor.whiteColor;
    label.font = [UIFont boldSystemFontOfSize:16];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [headerView addSubview:label];

    [NSLayoutConstraint activateConstraints:@[
        [label.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor constant:16],
        [label.centerYAnchor constraintEqualToAnchor:headerView.centerYAnchor]
    ]];

    return headerView;
}

#pragma mark - UICollectionViewDataSource
- (NSInteger)collectionView:(UICollectionView *)collectionView
     numberOfItemsInSection:(NSInteger)section {
    return self.projects.count;
}

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
                           cellForItemAtIndexPath:(NSIndexPath *)indexPath {

    UICollectionViewCell *cell =
        [collectionView dequeueReusableCellWithReuseIdentifier:@"ProjectCell"
                                                  forIndexPath:indexPath];

    // Remove old subviews (optional safeguard)
    for (UIView *v in cell.contentView.subviews) {
        [v removeFromSuperview];
    }

    // Get project
    SyncProject *project = self.projects[indexPath.item];

    // Background Image
    UIImageView *bgImageView = [[UIImageView alloc] init];
    bgImageView.contentMode = UIViewContentModeScaleAspectFill;
    bgImageView.clipsToBounds = YES;
    bgImageView.layer.cornerRadius = 12;
    bgImageView.translatesAutoresizingMaskIntoConstraints = NO;
    [cell.contentView addSubview:bgImageView];
    [NSLayoutConstraint activateConstraints:@[
        [bgImageView.topAnchor constraintEqualToAnchor:cell.contentView.topAnchor],
        [bgImageView.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor],
        [bgImageView.trailingAnchor constraintEqualToAnchor:cell.contentView.trailingAnchor],
        [bgImageView.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor],
    ]];

    // Project Name Label (bottom-left)
    UILabel *label = [[UILabel alloc] init];
    label.text = project.projectName;
    label.font = [UIFont boldSystemFontOfSize:16];
    label.textColor = UIColor.whiteColor;
    label.shadowColor = [UIColor blackColor];
    label.shadowOffset = CGSizeMake(0, 1);
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [cell.contentView addSubview:label];
    [NSLayoutConstraint activateConstraints:@[
        [label.leadingAnchor constraintEqualToAnchor:cell.contentView.leadingAnchor constant:12],
        [label.bottomAnchor constraintEqualToAnchor:cell.contentView.bottomAnchor constant:-12]
    ]];

    // Load image from API URL
    NSString *imageURLString = project.projectLogo;
    bgImageView.image = nil; // placeholder while loading

    if (imageURLString.length > 0) {
        NSURL *url = [NSURL URLWithString:imageURLString];
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url
                                                                 completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            if (data) {
                UIImage *image = [UIImage imageWithData:data];
                if (image) {
                    dispatch_async(dispatch_get_main_queue(), ^{
                        // Ensure the cell hasn't been reused for another index path
                        UICollectionViewCell *updateCell = [collectionView cellForItemAtIndexPath:indexPath];
                        if (updateCell) {
                            UIImageView *updateImageView = updateCell.contentView.subviews.firstObject; // bgImageView
                            if ([updateImageView isKindOfClass:[UIImageView class]]) {
                                ((UIImageView *)updateImageView).image = image;
                            }
                        }
                    });
                }
            }
        }];
        [task resume];
    }

    return cell;
}

#pragma mark - UICollectionViewDelegate
- (void)collectionView:(UICollectionView *)collectionView
didSelectItemAtIndexPath:(NSIndexPath *)indexPath {

    self.currentProject = self.projects[indexPath.item];
    [self.unitTableView reloadData];
    [self showSelectUnit];
}

#pragma mark - Project Data
- (void)loadProjectList {

    NSArray *storedProjects =
        [LocalStorage loadArrayForKey:kProjectListKey];

    if (storedProjects && storedProjects.count > 0) {
        NSLog(@"📦 Loaded PROJECT_LIST from storage");

        [self parseAndApplyProjects:storedProjects];
        return;
    }

    NSLog(@"🌐 No cached PROJECT_LIST, requesting from API");
    [self requestProjectList];
}

- (void)requestProjectList {

    [self showLoading:YES];

    [APIClient requestProjectList:^(BOOL success, NSDictionary *data, NSError *error) {
      
        // debug
        NSString *plainText = [NSString stringWithFormat:@"%@", data];
        NSString *docsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES).firstObject;
        NSString *filePath = [docsPath stringByAppendingPathComponent:@"projectList.txt"];
        [plainText writeToFile:filePath atomically:YES encoding:NSUTF8StringEncoding error:nil];
        NSLog(@"📁 projectList saved as plain text to: %@", filePath);

        [self showLoading:NO];

        if (error || !data) {
            NSLog(@"❌ Project list API failed: %@", error);
            return;
        }

        // RN parity: status_code check
        if (data[@"status_code"]) {
            NSLog(@"❌ API status error: %@", data[@"message"]);
            return;
        }

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

        NSArray *projects = data[@"Data"];
        if (![projects isKindOfClass:[NSArray class]]) {
            NSLog(@"❌ Invalid project list format");
            return;
        }

        // RN parity: save then reload from storage
        [LocalStorage saveArray:projects forKey:kProjectListKey];

        NSLog(@"✅ PROJECT_LIST saved to storage");

        [self parseAndApplyProjects:projects];
    }];
}

- (void)parseAndApplyProjects:(NSArray *)rawProjects {

    [self.projects removeAllObjects];

    for (NSDictionary *dict in rawProjects) {

        SyncProject *project = [SyncProject new];
        project.projectId = [dict[@"id"] description];
        project.projectName = dict[@"project_name"];
        project.projectLogo = dict[@"app_logo"];

        NSMutableArray *units = [NSMutableArray array];

        for (NSDictionary *unitDict in dict[@"unit"]) {

            SyncUnit *unit = [SyncUnit new];
            unit.planId = [unitDict[@"id"] description];

            NSString *name = unitDict[@"name"];
            if (!name || name.length == 0) {
                NSMutableArray *parts = [NSMutableArray array];
                if (unitDict[@"block"]) [parts addObject:unitDict[@"block"]];
                if (unitDict[@"level"]) [parts addObject:unitDict[@"level"]];
                if (unitDict[@"unit"])  [parts addObject:unitDict[@"unit"]];
                name = [parts componentsJoinedByString:@"-"];
            }

            unit.displayName = name;
            unit.projectId = project.projectId;
            unit.projectName = project.projectName;

            unit.project = @{
                @"id": project.projectId,
                @"project_name": project.projectName
            };

            unit.selected = NO;
            [units addObject:unit];
            [self updateOfflineUnitCountLabel];
            [self updateSelectProjectUnitCountLabel];
        }
        project.units = units;
        [self.projects addObject:project];
    }

    // Apply stored selections AFTER parsing
    [self applyStoredSelections];

    // Refresh UI
    [self.projectCollectionView reloadData];
    [self groupSelectedUnitsByProject];
    [self.offlineTableView reloadData];
}

- (void)applyStoredSelections {

    NSArray *stored =
        [LocalStorage loadArrayForKey:kSyncSelectedUnitsKey];
    if (!stored) return;

    for (NSDictionary *dict in stored) {

        NSString *planId = dict[@"plan_id"];
        NSDictionary *project = dict[@"project"];
        NSString *projectId = project[@"id"];

        for (SyncProject *p in self.projects) {
            if (![p.projectId isEqualToString:projectId]) continue;

            for (SyncUnit *u in p.units) {
                if ([u.planId isEqualToString:planId]) {
                    u.selected = YES;
                    if (![self isUnitAlreadySelected:u]) {
                        [self.selectedUnits addObject:u];
                    }
                    break;
                }
            }
        }
    }

    self.selectedUnitCount = self.selectedUnits.count;
}

#pragma mark - Screen State
- (void)setScreenState:(SyncProjectScreenState)state {
    _screenState = state;

    self.offlineUnitView.hidden = YES;
    self.selectProjectView.hidden = YES;
    self.selectUnitView.hidden = YES;

    switch (state) {
        case SyncProjectScreenStateOfflineUnit:
            self.offlineUnitView.hidden = NO;
            [self groupSelectedUnitsByProject];
            [self.offlineTableView reloadData];
            break;

        case SyncProjectScreenStateSelectProject:
            self.selectProjectView.hidden = NO;
            [self.projectCollectionView reloadData];
            break;

        case SyncProjectScreenStateSelectUnit:
            self.selectUnitView.hidden = NO;
            [self.unitTableView reloadData];
            break;
    }
}

#pragma mark - Helpers
- (void)onBack {
    switch (self.screenState) {
        case SyncProjectScreenStateOfflineUnit:
            [self dismissViewControllerAnimated:YES completion:nil];
            break;
        
        case SyncProjectScreenStateSelectProject:
            [self setScreenState:SyncProjectScreenStateOfflineUnit];
            break;

        case SyncProjectScreenStateSelectUnit:
            [self setScreenState:SyncProjectScreenStateSelectProject];
            break;
    }
}

- (void)hideAllContent {
    self.offlineUnitView.hidden = YES;
    self.selectProjectView.hidden = YES;
    self.selectUnitView.hidden = YES;
}

- (void)showOfflineUnit {
    [self setScreenState:SyncProjectScreenStateOfflineUnit];
    [self setHeaderTitle:@"Offline Unit"];
}

- (void)showSelectProject {
    [self hideAllContent];
    [self setHeaderTitle:@"Add Unit"];
    self.selectProjectView.hidden = NO;
}

- (void)showSelectUnit {
    [self setScreenState:SyncProjectScreenStateSelectUnit];
    [self setHeaderTitle:@"Add Unit"];
}

- (void)onAddUnit {
    [self showSelectProject];
}

- (void)onDone {
    NSLog(@"Selected units count: %lu",
          (unsigned long)self.selectedUnits.count);
    NSMutableArray *dictArray = [NSMutableArray array];
    for (SyncUnit *unit in self.selectedUnits) {
        [dictArray addObject:[self dictionaryFromUnit:unit]];
    }
    [self showOfflineUnit];
}

- (BOOL)canAddUnit {
    return self.selectedUnits.count < 10;
}

- (void)toggleUnit:(SyncUnit *)unit {

    if (unit.selected) {
        unit.selected = NO;

        NSPredicate *predicate =
            [NSPredicate predicateWithFormat:@"planId != %@", unit.planId];
        self.selectedUnits =
            [[self.selectedUnits filteredArrayUsingPredicate:predicate] mutableCopy];

    } else {
        if (![self canAddUnit]) {
            NSLog(@"only 10 units recommended");
            return;
        }

        if (![self isUnitAlreadySelected:unit]) {
            unit.selected = YES;
            [self.selectedUnits addObject:unit];
            [self updateOfflineUnitCountLabel];
            [self updateSelectProjectUnitCountLabel];
        }
    }

    self.hasChanges = YES;
    self.selectedUnitCount = self.selectedUnits.count;

    [self saveSelectedUnits];
}

- (void)showLoading:(BOOL)show {
    if (show) {
        [self.loadingView startAnimating];
    } else {
        [self.loadingView stopAnimating];
    }
}

- (NSDictionary *)dictionaryFromUnit:(SyncUnit *)unit {
    return @{
        @"plan_id": unit.planId ?: @"",
        @"sort_name": unit.displayName ?: @"",
        @"project": @{
            @"id": unit.projectId ?: @"",
            @"project_name": unit.projectName ?: @""
        }
    };
}

- (SyncUnit *)unitFromDictionary:(NSDictionary *)dict {
    SyncUnit *unit = [SyncUnit new];
    unit.planId = dict[@"plan_id"];
    unit.displayName = dict[@"sort_name"];

    NSDictionary *project = dict[@"project"];
    unit.projectId = project[@"id"];
    unit.projectName = project[@"project_name"];

    unit.selected = YES;
    return unit;
}

- (void)saveSelectedUnits {
    NSMutableArray *array = [NSMutableArray array];

    for (SyncUnit *unit in self.selectedUnits) {
        [array addObject:[self dictionaryFromUnit:unit]];
    }

    [LocalStorage saveArray:array forKey:kSyncSelectedUnitsKey];
}

- (void)loadSelectedUnits {
    NSArray *stored = [LocalStorage loadArrayForKey:kSyncSelectedUnitsKey];
    if (!stored) return;

    [self.selectedUnits removeAllObjects];

    for (NSDictionary *dict in stored) {
        SyncUnit *unit = [self unitFromDictionary:dict];
        if (![self isUnitAlreadySelected:unit]) {
            [self.selectedUnits addObject:unit];
        }
    }

    self.selectedUnitCount = self.selectedUnits.count;
}

- (BOOL)isUnitAlreadySelected:(SyncUnit *)unit {
    for (SyncUnit *u in self.selectedUnits) {
        if ([u.planId isEqualToString:unit.planId]) {
            return YES;
        }
    }
    return NO;
}

- (void)onDeleteUnit:(UIButton *)sender {

    NSInteger index = sender.tag;
    if (index < 0 || index >= self.selectedUnits.count) return;

    SyncUnit *unit = self.selectedUnits[index];

    unit.selected = NO;
    [self.selectedUnits removeObjectAtIndex:index];
    [self updateOfflineUnitCountLabel];
    [self updateSelectProjectUnitCountLabel];


    self.selectedUnitCount = self.selectedUnits.count;
    self.hasChanges = YES;

    [self saveSelectedUnits];
    [self groupSelectedUnitsByProject];
    [self.offlineTableView reloadData];
}

- (void)updateOfflineUnitCountLabel {
    NSUInteger count = self.selectedUnits.count;
    if (count == 0) {
        self.offlineUnitCountLabel.text = @"No Units Selected";
    } else if (count == 1) {
        self.offlineUnitCountLabel.text = @"1 Unit Selected";
    } else {
        self.offlineUnitCountLabel.text = [NSString stringWithFormat:@"%lu Units Selected", (unsigned long)count];
    }
}

- (void)groupSelectedUnitsByProject {
    NSLog(@"[GROUP] selectedUnits count = %lu",
          (unsigned long)self.selectedUnits.count);

    NSMutableDictionary<NSString *, NSMutableArray<SyncUnit *> *> *dict =
        [NSMutableDictionary new];
    NSLog(@"[GROUP] projects found = %@", dict.allKeys);


    for (SyncUnit *unit in self.selectedUnits) {
      for (SyncUnit *unit in self.selectedUnits) {
          NSLog(@"[UNIT] projectName=%@ displayName=%@ projectId=%@",
                unit.projectName,
                unit.displayName,
                unit.projectId);
      }

        if (!dict[unit.projectName]) {
            dict[unit.projectName] = [NSMutableArray new];
        }
        [dict[unit.projectName] addObject:unit];
    }

    // Sort units inside each project
    for (NSString *projectName in dict.allKeys) {
        NSArray *sortedUnits =
            [dict[projectName] sortedArrayUsingComparator:^NSComparisonResult(SyncUnit *a, SyncUnit *b) {
                return [a.displayName localizedCaseInsensitiveCompare:b.displayName];
            }];
        dict[projectName] = [sortedUnits mutableCopy];
    }

    self.selectedUnitsByProject = dict;

    // ✅ DEFINE the sorted keys properly
    NSArray *sortedProjectNames =
        [[dict allKeys] sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];

    self.projectNamesSorted = sortedProjectNames;

    // Optional: hide table when empty
    self.offlineTableView.hidden = (self.projectNamesSorted.count == 0);
}


- (void)onDeleteUnitFromProject:(UIButton *)sender {
    // Find section and row
    CGPoint buttonPosition = [sender convertPoint:CGPointZero toView:self.offlineTableView];
    NSIndexPath *indexPath = [self.offlineTableView indexPathForRowAtPoint:buttonPosition];
    if (!indexPath) return;

    NSString *projectName = self.projectNamesSorted[indexPath.section];
    SyncUnit *unit = self.selectedUnitsByProject[projectName][indexPath.row];

    unit.selected = NO;
    [self.selectedUnits removeObject:unit];

    [self updateOfflineUnitCountLabel];
    [self updateSelectProjectUnitCountLabel];

    [self groupSelectedUnitsByProject];
    [self.offlineTableView reloadData];
}

- (void)updateSelectProjectUnitCountLabel {
    NSUInteger count = self.selectedUnits.count;
    if (count == 0) {
        self.selectProjectUnitCountLabel.text = @"No Units Selected";
    } else {
        self.selectProjectUnitCountLabel.text = [NSString stringWithFormat:@"%lu Units Selected", (unsigned long)count];
    }
}

- (void)onUnitCheckboxChanged:(NSNotification *)notification {
    SyncUnit *unit = notification.object;
    if (!unit) return;

    if (unit.selected) {
        if (![self isUnitAlreadySelected:unit]) {
            [self.selectedUnits addObject:unit];
        }
    } else {
        [self.selectedUnits removeObject:unit];
    }

    [self updateOfflineUnitCountLabel];
    [self updateSelectProjectUnitCountLabel];
    [self groupSelectedUnitsByProject];
    [self saveSelectedUnits];

    [self.unitTableView reloadData];
}

@end
