//
//  BarChartView.cpp
//  react-native-charts
//
//  Created by Peter Vu on 12/01/2023.
//

#import "BarChartView.h"

#import <react/renderer/components/RNChartsViewSpec/ComponentDescriptors.h>
#import <react/renderer/components/RNChartsViewSpec/EventEmitters.h>
#import <react/renderer/components/RNChartsViewSpec/Props.h>
#import <react/renderer/components/RNChartsViewSpec/RCTComponentViewHelpers.h>
#import "RCTFabricComponentsPlugins.h"
#import "RNCharts-Swift.h"
#import "NumberFormatterAxisValueFormatter.h"
#import <math.h>

using namespace facebook::react;

@interface RNBarChartView () <RCTRNBarChartViewViewProtocol>

@end

@interface CustomLabelsXAxisValueFormatter : NSObject <ChartAxisValueFormatter>
@property (nonatomic, strong) NSArray<NSString *> *labels;
- (instancetype)initWithLabels:(NSArray<NSString *> *)labels;
@end

@implementation RNBarChartView {
	BarChartView * _view;
}

+ (ComponentDescriptorProvider)componentDescriptorProvider
{
	return concreteComponentDescriptorProvider<RNBarChartViewComponentDescriptor>();
}

- (instancetype)initWithFrame:(CGRect)frame
{
  if (self = [super initWithFrame:frame]) {
	static const auto defaultProps = std::make_shared<const RNBarChartViewProps>();
	_props = defaultProps;
	_view = [[BarChartView alloc] init];
	_view.chartDescription.enabled = NO;
	  _view.pinchZoomEnabled = NO;
	  _view.drawBordersEnabled = NO;
	  _view.doubleTapToZoomEnabled = NO;
	  _view.scaleYEnabled = NO;
	  _view.scaleXEnabled = NO;
	  _view.dragYEnabled = NO;
	  _view.drawGridBackgroundEnabled = NO;
	  _view.highlightPerDragEnabled = NO;
	  _view.highlightPerTapEnabled = NO;
	  _view.gridBackgroundColor = UIColor.whiteColor;
	  _view.legend.enabled = NO;
	  _view.xAxis.centerAxisLabelsEnabled = YES;
//	  _view.xAxis.granularityEnabled = YES;
//	  _view.xAxis.granularity = 1;
	  _view.xAxis.yOffset = 6;
	  _view.xAxis.axisLineColor = UIColor.clearColor;
	  _view.rightAxis.enabled = NO;
	  _view.leftAxis.axisMinimum = 0;
	  _view.leftAxis.gridLineWidth = 1;
	  _view.leftAxis.axisLineColor = UIColor.clearColor;
	  [_view.leftAxis setLabelPosition:YAxisLabelPositionOutsideChart];
	  _view.leftAxis.valueFormatter = [[NumberFormatterAxisValueFormatter alloc] init];
//
	  
	  _view.chartDescription.enabled = NO;
	  _view.drawGridBackgroundEnabled = NO;
	  _view.drawBarShadowEnabled = NO;
	  _view.highlightFullBarEnabled = NO;
	  
	  // Configure x-axis
	  ChartXAxis *xAxis = _view.xAxis;
	  xAxis.labelPosition = XAxisLabelPositionBottom;
	  xAxis.drawGridLinesEnabled = NO;
	  xAxis.granularity = 1.0;
//	  xAxis.labelCount = 7;
	  xAxis.centerAxisLabelsEnabled = YES;
	  
	  ChartYAxis *leftAxis = _view.leftAxis;
	  leftAxis.drawGridLinesEnabled = YES;
	  leftAxis.axisMinimum = 0.0;

	  _view.rightAxis.enabled = NO;
		  
	  // Configure legend
	  _view.legend.enabled = NO;
	  _view.xAxis.avoidFirstLastClippingEnabled = YES;
	  
	self.contentView = _view;

  }

  return self;
}


- (void)updateProps:(Props::Shared const &)props oldProps:(Props::Shared const &)oldProps
{
	const auto &oldViewProps = *std::static_pointer_cast<RNBarChartViewProps const>(_props);
	const auto &newViewProps = *std::static_pointer_cast<RNBarChartViewProps const>(props);
//
	_view.xAxis.axisMaxLabels = 5;
	_view.leftAxis.labelFont = [UIFont systemFontOfSize:newViewProps.yAxis.labels.style.fontSize];
	_view.leftAxis.labelTextColor = [self hexStringToColor:[NSString stringWithUTF8String:newViewProps.yAxis.labels.style.color.c_str()]];
	_view.leftAxis.axisLineWidth = newViewProps.yAxis.gridLineWidth;
	_view.leftAxis.gridLineWidth = newViewProps.yAxis.gridLineWidth;
	_view.leftAxis.gridColor = [self hexStringToColor:[NSString stringWithUTF8String:newViewProps.yAxis.gridLineColor.c_str()]];
//
	_view.xAxis.gridLineWidth = newViewProps.xAxis.lineWidth;
	_view.xAxis.gridColor = [self hexStringToColor:[NSString stringWithUTF8String:newViewProps.xAxis.lineColor.c_str()]];
	_view.xAxis.labelTextColor = [self hexStringToColor:[NSString stringWithUTF8String:newViewProps.xAxis.labels.style.color.c_str()]];
	_view.xAxis.labelFont = [UIFont systemFontOfSize:newViewProps.xAxis.labels.style.fontSize];
	[_view.xAxis setDrawGridLinesEnabled:YES];
//
//	NSMutableArray<BarChartDataSet*>* dataSets = [[NSMutableArray alloc] init];
//	for (auto it = begin (newViewProps.seriesData.series.data); it != end (newViewProps.seriesData.series.data); ++it) {
//		NSMutableArray<BarChartDataEntry*>* entries = [[NSMutableArray alloc] init];
//		for (auto eIdx = begin (it->data); eIdx != end (it->data); ++eIdx) {
//			BarChartDataEntry* newEntry = [[BarChartDataEntry alloc] initWithX:eIdx->x y:eIdx->y];
//			[entries addObject:newEntry];
//		}
//
//		BarChartDataSet* dataSet = [[BarChartDataSet alloc] initWithEntries:entries];
//
//		// it->color from std::string to NSString
//		NSString* colorString = [NSString stringWithUTF8String:it->color.c_str()];
//		dataSet.colors = @[[self hexStringToColor:colorString]];
//		dataSet.drawValuesEnabled = NO;
//		[dataSets addObject:dataSet];
//	}
//
//	BarChartData* data = [[BarChartData alloc] initWithDataSets:dataSets];
////	data.barWidth = 0.7;
//
	NSMutableArray<NSString*>* categories = [[NSMutableArray alloc] init];
	for (auto it = begin (newViewProps.xAxis.categories); it != end (newViewProps.xAxis.categories); ++it) {
		[categories addObject:[NSString stringWithUTF8String:it->c_str()]];
	}

	_view.xAxis.valueFormatter = [[CustomLabelsXAxisValueFormatter alloc] initWithLabels: categories];
	
    std::string dataJsonString = newViewProps.seriesJsonData.series.data;
    NSString *convertedDataJsonString = [NSString stringWithUTF8String:dataJsonString.c_str()];
        
    NSError *error;
    NSDictionary *parsedData = [NSJSONSerialization JSONObjectWithData:[convertedDataJsonString dataUsingEncoding:NSUTF8StringEncoding] options:kNilOptions error:&error];
        
    NSArray *dataValuesArray = [parsedData allValues];
    
    NSMutableArray *dataSets = [[NSMutableArray alloc] init];
    
    for (int dataSetIndex = 0; dataSetIndex < [dataValuesArray count]; dataSetIndex++) {
        NSDictionary *dataSetValue = dataValuesArray[dataSetIndex];
        NSMutableArray *entries = [[NSMutableArray alloc] init];
        
        NSArray *dataItemValue = [dataSetValue[@"data"] allValues];
        
        // Create data entries for each dataset
        for (int entryIndex = 0; entryIndex < [dataItemValue count]; entryIndex++) {
            NSDictionary *dataEntryValue = dataItemValue[entryIndex];
            NSNumber *xValue = dataEntryValue[@"x"];
            NSNumber *yValue = dataEntryValue[@"y"];
            BarChartDataEntry *entry = [[BarChartDataEntry alloc] initWithX:xValue.doubleValue y:yValue.doubleValue];
            [entries addObject:entry];
        }
        
        BarChartDataSet *dataSet = [[BarChartDataSet alloc] initWithEntries:entries];
        
        NSString *colorStringValue = dataSetValue[@"color"];

//        NSString* colorString = [NSString stringWithUTF8String:colorStringValue.c_str()];
        dataSet.colors = @[[self hexStringToColor:colorStringValue]];
        dataSet.drawValuesEnabled = NO;
        
        [dataSets addObject:dataSet];
    }
    
//    NSMutableArray *dataSets = [[NSMutableArray alloc] init];
//	// Loop for creating multiple datasets
//	for (int dataSetIndex = 0; dataSetIndex < newViewProps.seriesData.series.data.size(); dataSetIndex++) {
//		NSMutableArray *entries = [[NSMutableArray alloc] init];
//
//		// Create data entries for each dataset
//		for (int entryIndex = 0; entryIndex < newViewProps.seriesData.series.data[dataSetIndex].data.size(); entryIndex++) {
//			BarChartDataEntry *entry = [[BarChartDataEntry alloc] initWithX:newViewProps.seriesData.series.data[dataSetIndex].data[entryIndex].x y:newViewProps.seriesData.series.data[dataSetIndex].data[entryIndex].y];
//			[entries addObject:entry];
//		}
//
//		BarChartDataSet *dataSet = [[BarChartDataSet alloc] initWithEntries:entries];
//		
//		NSString* colorString = [NSString stringWithUTF8String:newViewProps.seriesData.series.data[dataSetIndex].color.c_str()];
//		dataSet.colors = @[[self hexStringToColor:colorString]];
//		dataSet.drawValuesEnabled = NO;
//		
//		[dataSets addObject:dataSet];
//	}
	
	double barWidth = 0.6;
	double groupSpace = 0.2;

	BarChartData *barChartData = [[BarChartData alloc] initWithDataSets:dataSets];
	barChartData.barWidth = barWidth;
	
	_view.xAxis.axisMinimum = 0.0;
	_view.xAxis.axisMaximum =  [barChartData groupWidthWithGroupSpace:groupSpace barSpace:0] * categories.count;
	
	[barChartData groupBarsFromX:0 groupSpace:groupSpace barSpace:0];
	_view.xAxis.granularity = _view.xAxis.axisMaximum / double(categories.count);
	_view.data = barChartData;
	
	[_view notifyDataSetChanged];
	
	[_view setVisibleXRangeMaximum:4];
	
	[super updateProps:props oldProps:oldProps];
}

Class<RCTComponentViewProtocol> RNBarChartViewCls(void)
{
	return RNBarChartView.class;
}

- hexStringToColor:(NSString *)stringToConvert
{
	NSString *noHashString = [stringToConvert stringByReplacingOccurrencesOfString:@"#" withString:@""];
	NSScanner *stringScanner = [NSScanner scannerWithString:noHashString];
	
	unsigned hex;
	if (![stringScanner scanHexInt:&hex]) return nil;
	int r = (hex >> 16) & 0xFF;
	int g = (hex >> 8) & 0xFF;
	int b = (hex) & 0xFF;
	
	return [UIColor colorWithRed:r / 255.0f green:g / 255.0f blue:b / 255.0f alpha:1.0f];
}

- (double)calculateXAxisMaximumForBarWidth:(double)barWidth groupSpace:(double)groupSpace numberOfBarsPerGroup:(int)numberOfBarsPerGroup numberOfGroups:(int)numberOfGroups {
	double xAxisMaximum = (barWidth * numberOfBarsPerGroup + groupSpace) * numberOfGroups - groupSpace;
	return xAxisMaximum;
}

@end





@implementation CustomLabelsXAxisValueFormatter

- (instancetype)initWithLabels:(NSArray<NSString *> *)labels {
	self = [super init];
	if (self) {
		_labels = labels;
	}
	return self;
}

- (NSString *)stringForValue:(double)value axis:(ChartAxisBase *)axis {
	
	NSUInteger count = self.labels.count;
	
	if (!axis || count == 0) {
		return @"";
	}
	
	double factor = axis.axisMaximum / (double)count;
	
	NSInteger index = (NSInteger)round(value / factor);
	
	if (index >= 0 && index < count) {
		return self.labels[index];
	}
	
	return @"";
}

@end
