import 'package:flutter/material.dart';
import 'package:flutter_custom_toolbox/flutter_toolbox.dart';
import 'package:fl_chart/fl_chart.dart';

import 'package:scrobbles/models/data/topartists.dart';
import 'package:scrobbles/ui/widgets/abstracts/custom_line_chart.dart';

class ChartTopArtistsStream extends CustomLineChart {
  const ChartTopArtistsStream({super.key, required this.chartData});

  final TopArtistsData chartData;

  @override
  double get verticalTicksInterval => 10;
  @override
  String get verticalAxisTitleSuffix => '%';

  @override
  Widget build(BuildContext context) {
    if (chartData.topArtistsStream.keys.isEmpty) {
      return SizedBox(
        height: chartHeight,
      );
    }

    final horizontalScale = getHorizontalScaleFromDates(chartData.topArtistsStream.keys);

    return SizedBox(
      height: chartHeight,
      child: LineChart(
        LineChartData(
          lineBarsData: getDataStreamLine(),
          betweenBarsData: getBetweenBarsData(),
          borderData: noBorderData,
          gridData: horizontalGridData,
          titlesData: getTitlesData(),
          lineTouchData: const LineTouchData(enabled: false),
          minX: horizontalScale['min'],
          maxX: horizontalScale['max'],
          maxY: getNextRoundNumber(getMaxVerticalValue(), verticalTicksInterval),
          minY: 0,
        ),
        duration: const Duration(milliseconds: 250),
      ),
    );
  }

  double getMaxVerticalValue() {
    double maxValue = 0;

    for (var dateAsString in chartData.topArtistsStream.keys) {
      double totalValue = 0.0;
      final List<TopArtistsStreamDataValue> artists =
          chartData.topArtistsStream[dateAsString] ?? [];

      for (var artist in artists) {
        final double value = artist.value;
        totalValue = totalValue + value;
      }

      if (totalValue > maxValue) {
        maxValue = totalValue;
      }
    }

    return maxValue;
  }

  List<LineChartBarData> getDataStreamLine() {
    final int artistsCount =
        chartData.topArtistsStream[chartData.topArtistsStream.keys.first]?.length ?? 0;

    List<LineChartBarData> lines = [];

    LineChartBarData getZeroHorizontalLine() {
      final baseColor = getColorFromIndex(0);
      final borderColor = baseColor.darken(20);

      List<FlSpot> spots = [];

      for (var dateAsString in chartData.topArtistsStream.keys) {
        final double date = DateTime.parse(dateAsString).millisecondsSinceEpoch.toDouble();
        spots.add(FlSpot(date, 0));
      }

      return LineChartBarData(
        color: borderColor,
        dotData: const FlDotData(show: false),
        spots: spots,
      );
    }

    // First horizontal "zero" line
    lines.add(getZeroHorizontalLine());

    LineChartBarData getLinesFromIndex(int index) {
      final baseColor = getColorFromIndex(index);
      final borderColor = baseColor.darken(20);

      List<FlSpot> spots = [];

      for (var dateAsString in chartData.topArtistsStream.keys) {
        final double date = DateTime.parse(dateAsString).millisecondsSinceEpoch.toDouble();

        List<TopArtistsStreamDataValue> artists =
            chartData.topArtistsStream[dateAsString] ?? [];

        double value = 0;
        for (int i = 0; i <= index; i++) {
          value = value + artists[i].value;
        }

        spots.add(FlSpot(date, value));
      }

      return LineChartBarData(
        isCurved: true,
        curveSmoothness: 0.25,
        color: borderColor,
        dotData: const FlDotData(show: false),
        spots: spots,
      );
    }

    Iterable<int>.generate(artistsCount)
        .toList()
        .map((index) => lines.add(getLinesFromIndex(index)))
        .toList();

    return lines;
  }

  List<BetweenBarsData> getBetweenBarsData() {
    final int artistsCount =
        chartData.topArtistsStream[chartData.topArtistsStream.keys.first]?.length ?? 0;

    return Iterable<int>.generate(artistsCount)
        .toList()
        .map((index) => BetweenBarsData(
              fromIndex: index,
              toIndex: index + 1,
              color: getColorFromIndex(index),
            ))
        .toList();
  }

  @override
  Widget getHorizontalTitlesWidget(double value, TitleMeta meta) {
    return getHorizontalTitlesWidgetWithDate(value, meta);
  }
}