import { StringCaser } from "@/utils/utils";
import { buildFormApiArgs, underscoreToPascalCase } from "./form";

export function findGraphComponents(data, result = []) {

  if (!Array.isArray(data)) data = [data];
  for (const item of data) {
    if ("components" in item) {
      findGraphComponents(item.components, result);
    }
    if ("children" in item) {
      findGraphComponents(item.children, result);
    }
    if (
      item.name === "BarChart" ||
      item.name === "PieChart" ||
      item.name === "LineChart"
    ) {
      result.push(item);
    }
  }

  return result;
}

function convertFunctionName(inputString) {
  const withoutEdit = inputString.replace("get", "");
  const withoutSpaces = withoutEdit.replace(/\s+/g, "");

  const camelCaseString = withoutSpaces.charAt(0) + withoutSpaces.slice(1);

  const resultString = `get${camelCaseString}`;

  return resultString;
}

export const buildGraphImports = (fragment) => {
  if (findGraphComponents(fragment)?.length == 0) return "";
  return `
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.ui.setupWithNavController
import Manaknight.databinding.ActivityMainBinding
import android.graphics.Color
import com.github.mikephil.charting.animation.Easing
import com.github.mikephil.charting.components.Legend
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.utils.ColorTemplate
import com.manaknight.app.model.remote.AnimalModel
${findGraphComponents(fragment).some(
    (component) => component.name === "PieChart"
  )
      ? `
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.data.PieData
import com.github.mikephil.charting.data.PieDataSet
import com.github.mikephil.charting.data.PieEntry
`
      : ""
    }
${findGraphComponents(fragment).some(
      (component) => component.name === "LineChart"
    )
      ? `
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.github.mikephil.charting.data.Entry
`
      : ""
    }
${findGraphComponents(fragment).some(
      (component) => component.name === "BarChart"
    )
      ? `
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.data.BarData
import com.github.mikephil.charting.data.BarDataSet
import com.github.mikephil.charting.data.BarEntry
`
      : ""
    }
`;

};

export const generateGraphFragmentBinding = (fragment) => {
  if (findGraphComponents(fragment).length == 0) return "";

  return `
        retrieveRecordsAndPopulateCharts()`;
};

export const generateGraphFunction = (fragment, configuration) => {
  if (findGraphComponents(fragment).length == 0) return "";

  const field = findGraphComponents(fragment);

  const { api } = configuration;


  let sourceApi = [];
  field.map((f) => {
    const propValue = f?.props?.source;
    const matchingApi = api?.find((apiItem) => {
      return apiItem?.id === propValue;
    });

    if (matchingApi) {
      sourceApi = matchingApi;
    }
  });

  let newField = [];
  if (sourceApi.length) {
    sourceApi?.inputs?.forEach((field) => {
      let formatedField = underscoreToPascalCase(field?.name);

      let formattedType = field?.dataType === "Integer?" ? "Int?" : field?.dataType;

      newField.push(`${formatedField}: ${formattedType}`);
    });
  }


  let typedFields = newField.join(", ");

  if (sourceApi?.inputs?.length) {
    return `
        override fun onResume() {
          super.onResume()
      }

      override fun onDestroy() {
          super.onDestroy()
      }

      private fun ${StringCaser(sourceApi.name, {
      separator: "",
      casetype: "camelCase",
    })}(${typedFields}) {
          requireActivity().hideSoftKeyboard()

          baasViewModel.${StringCaser(sourceApi?.name, {
      casetype: "camelCase",
    })}(${buildFormApiArgs(sourceApi)}).observe(viewLifecycleOwner) {
              when (it.status) {
                  Status.ERROR -> snackBar(it.message ?: getString(R.string.something_went_wrong))
                  Status.LOADING -> {
                      snackBar("Logging in...")
                  }

                  Status.SUCCESS -> {
                      val data = it.data
                      data?.let { it1 -> Log.d("", it1.message)}
                  }
              }
          }
      }
      

      fun retreiveAnimals():List<AnimalModel> {

          val record1 =  AnimalModel(1, "Lion", 470, 7, 87)
          val record2 =  AnimalModel(2, "Impala", 1879, 10, 90)
          val record3 =  AnimalModel(3, "Leopard", 570, 13, 89)
          val record4 =  AnimalModel(4, "Crocodile", 150, 30, 66)

          return listOf(record1, record2, record3, record4)

      }

      fun retrieveRecordsAndPopulateCharts() {


          val animal: List<AnimalModel> = retreiveAnimals()
          val animalIDArray = Array<Int>(animal.size) { 0 }
          ${findGraphComponents(fragment).some(
      (component) => component.name === "PieChart"
    )
        ? `val animalNameArray = Array<String>(animal.size) { "natgeo" }
          val animalNumberArray = Array<Int>(animal.size) { 0 }`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? ` val animalAgeArray = Array<Int>(animal.size) { 0 }`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `val animalGrowthArray = Array<Int>(animal.size) { 0 }`
        : ""
      }

          //add the records till done
          var index = 0
          for (a in animal) {
              animalIDArray[index] = a.animalId
          ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `animalNameArray[index] = a.animalName
              animalNumberArray[index] = a.totNumber`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `animalAgeArray[index] = a.avgAge`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `animalGrowthArray[index] = a.avgGrowth
              index++`
        : ""
      }    
              
          }
          //call the methods for populating the charts
            ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `populatePieChart(animalNumberArray, animalNameArray)`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `populateBarChart(animalAgeArray)`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `populateLineChart(animalGrowthArray)`
        : ""
      }
      }

      ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `
          private fun populatePieChart(values: Array<Int>, labels: Array<String>) {
          //an array to store the pie slices entry
          val ourPieEntry = ArrayList<PieEntry>()
          var i = 0

          for (entry in values) {
              //converting to float
              var value = values[i].toFloat()
              var label = labels[i]
              //adding each value to the pieentry array
              ourPieEntry.add(PieEntry(value, label))
              i++
          }

          //assigning color to each slices
          val pieShades: ArrayList<Int> = ArrayList()
          pieShades.add(Color.parseColor("#0E2DEC"))
          pieShades.add(Color.parseColor("#B7520E"))
          pieShades.add(Color.parseColor("#5E6D4E"))
          pieShades.add(Color.parseColor("#DA1F12"))

          //add values to the pie dataset and passing them to the constructor
          val ourSet = PieDataSet(ourPieEntry, "")
          val data = PieData(ourSet)

          //setting the slices divider width
          ourSet.sliceSpace = 1f

          //populating the colors and data
          ourSet.colors = pieShades
          binding.ourPieChart.data = data
          //setting color and size of text
          data.setValueTextColor(Color.WHITE)
          data.setValueTextSize(10f)

          //add an animation when rendering the pie chart
          binding.ourPieChart.animateY(1400, Easing.EaseInOutQuad)
          //disabling center hole
          binding.ourPieChart.isDrawHoleEnabled = false
          //do not show description text
          binding.ourPieChart.description.isEnabled = false
          //legend enabled and its various appearance settings
          binding.ourPieChart.legend.isEnabled = true
          binding.ourPieChart.legend.orientation = Legend.LegendOrientation.HORIZONTAL
          binding.ourPieChart.legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER
          binding.ourPieChart.legend.isWordWrapEnabled = true

          //dont show the text values on slices e.g Antelope, impala etc
          binding.ourPieChart.setDrawEntryLabels(false)
          //refreshing the chart
          binding.ourPieChart.invalidate()

      }
          `
        : ""
      }

   ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `
       private fun populateBarChart(values: Array<Int>) {
       //adding values
       val ourBarEntries: ArrayList<BarEntry> = ArrayList()
       var i = 0

       for (entry in values) {
           var value = values[i].toFloat()
           ourBarEntries.add(BarEntry(i.toFloat(), value))
           i++
       }


       val barDataSet = BarDataSet(ourBarEntries, "")
       //set a template coloring
       barDataSet.setColors(*ColorTemplate.COLORFUL_COLORS)
       val data = BarData(barDataSet)
       binding.ourBarChart.data = data
       //setting the x-axis
       val xAxis: XAxis = binding.ourBarChart.xAxis
       //calling methods to hide x-axis gridlines
       binding.ourBarChart.axisLeft.setDrawGridLines(false)
       xAxis.setDrawGridLines(false)
       xAxis.setDrawAxisLine(false)

       //remove legend
       binding.ourBarChart.legend.isEnabled = false

       //remove description label
       binding.ourBarChart.description.isEnabled = false

       //add animation
       binding.ourBarChart.animateY(3000)
       //refresh the chart
       binding.ourBarChart.invalidate()
   }
       `
        : ""
      }

   ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `
       private fun populateLineChart(values: Array<Int>) {
       val ourLineChartEntries: ArrayList<Entry> = ArrayList()

       var i = 0

       for (entry in values) {
           var value = values[i].toFloat()
           ourLineChartEntries.add(Entry(i.toFloat(), value))
           i++
       }
       val lineDataSet = LineDataSet(ourLineChartEntries, "")
       lineDataSet.setColors(*ColorTemplate.PASTEL_COLORS)
       val data = LineData(lineDataSet)

       binding.ourLineChart.axisLeft.setDrawGridLines(false)
       val xAxis: XAxis = binding.ourLineChart.xAxis
       xAxis.setDrawGridLines(false)
       xAxis.setDrawAxisLine(false)
       binding.ourLineChart.legend.isEnabled = false

       //remove description label
       binding.ourLineChart.description.isEnabled = false

       //add animation
       binding.ourLineChart.animateX(1000, Easing.EaseInSine)
       binding.ourLineChart.data = data
       //refresh
       binding.ourLineChart.invalidate()
   }
       `
        : ""
      }
   `;
  } else {
    return `
        override fun onResume() {
          super.onResume()
      }

      override fun onDestroy() {
          super.onDestroy()
      }
      

      fun retreiveAnimals():List<AnimalModel> {

          val record1 =  AnimalModel(1, "Lion", 470, 7, 87)
          val record2 =  AnimalModel(2, "Impala", 1879, 10, 90)
          val record3 =  AnimalModel(3, "Leopard", 570, 13, 89)
          val record4 =  AnimalModel(4, "Crocodile", 150, 30, 66)

          return listOf(record1, record2, record3, record4)

      }

      fun retrieveRecordsAndPopulateCharts() {


          val animal: List<AnimalModel> = retreiveAnimals()
          val animalIDArray = Array<Int>(animal.size) { 0 }
          ${findGraphComponents(fragment).some(
      (component) => component.name === "PieChart"
    )
        ? `val animalNameArray = Array<String>(animal.size) { "natgeo" }
          val animalNumberArray = Array<Int>(animal.size) { 0 }`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? ` val animalAgeArray = Array<Int>(animal.size) { 0 }`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `val animalGrowthArray = Array<Int>(animal.size) { 0 }`
        : ""
      }

          //add the records till done
          var index = 0
          for (a in animal) {
              animalIDArray[index] = a.animalId
          ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `animalNameArray[index] = a.animalName
              animalNumberArray[index] = a.totNumber`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `animalAgeArray[index] = a.avgAge`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `animalGrowthArray[index] = a.avgGrowth
              index++`
        : ""
      }    
              
          }
          //call the methods for populating the charts
            ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `populatePieChart(animalNumberArray, animalNameArray)`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `populateBarChart(animalAgeArray)`
        : ""
      }
          ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `populateLineChart(animalGrowthArray)`
        : ""
      }
      }

      ${findGraphComponents(fragment).some(
        (component) => component.name === "PieChart"
      )
        ? `
          private fun populatePieChart(values: Array<Int>, labels: Array<String>) {
          //an array to store the pie slices entry
          val ourPieEntry = ArrayList<PieEntry>()
          var i = 0

          for (entry in values) {
              //converting to float
              var value = values[i].toFloat()
              var label = labels[i]
              //adding each value to the pieentry array
              ourPieEntry.add(PieEntry(value, label))
              i++
          }

          //assigning color to each slices
          val pieShades: ArrayList<Int> = ArrayList()
          pieShades.add(Color.parseColor("#0E2DEC"))
          pieShades.add(Color.parseColor("#B7520E"))
          pieShades.add(Color.parseColor("#5E6D4E"))
          pieShades.add(Color.parseColor("#DA1F12"))

          //add values to the pie dataset and passing them to the constructor
          val ourSet = PieDataSet(ourPieEntry, "")
          val data = PieData(ourSet)

          //setting the slices divider width
          ourSet.sliceSpace = 1f

          //populating the colors and data
          ourSet.colors = pieShades
          binding.ourPieChart.data = data
          //setting color and size of text
          data.setValueTextColor(Color.WHITE)
          data.setValueTextSize(10f)

          //add an animation when rendering the pie chart
          binding.ourPieChart.animateY(1400, Easing.EaseInOutQuad)
          //disabling center hole
          binding.ourPieChart.isDrawHoleEnabled = false
          //do not show description text
          binding.ourPieChart.description.isEnabled = false
          //legend enabled and its various appearance settings
          binding.ourPieChart.legend.isEnabled = true
          binding.ourPieChart.legend.orientation = Legend.LegendOrientation.HORIZONTAL
          binding.ourPieChart.legend.horizontalAlignment = Legend.LegendHorizontalAlignment.CENTER
          binding.ourPieChart.legend.isWordWrapEnabled = true

          //dont show the text values on slices e.g Antelope, impala etc
          binding.ourPieChart.setDrawEntryLabels(false)
          //refreshing the chart
          binding.ourPieChart.invalidate()

      }
          `
        : ""
      }

   ${findGraphComponents(fragment).some(
        (component) => component.name === "BarChart"
      )
        ? `
       private fun populateBarChart(values: Array<Int>) {
       //adding values
       val ourBarEntries: ArrayList<BarEntry> = ArrayList()
       var i = 0

       for (entry in values) {
           var value = values[i].toFloat()
           ourBarEntries.add(BarEntry(i.toFloat(), value))
           i++
       }


       val barDataSet = BarDataSet(ourBarEntries, "")
       //set a template coloring
       barDataSet.setColors(*ColorTemplate.COLORFUL_COLORS)
       val data = BarData(barDataSet)
       binding.ourBarChart.data = data
       //setting the x-axis
       val xAxis: XAxis = binding.ourBarChart.xAxis
       //calling methods to hide x-axis gridlines
       binding.ourBarChart.axisLeft.setDrawGridLines(false)
       xAxis.setDrawGridLines(false)
       xAxis.setDrawAxisLine(false)

       //remove legend
       binding.ourBarChart.legend.isEnabled = false

       //remove description label
       binding.ourBarChart.description.isEnabled = false

       //add animation
       binding.ourBarChart.animateY(3000)
       //refresh the chart
       binding.ourBarChart.invalidate()
   }
       `
        : ""
      }

   ${findGraphComponents(fragment).some(
        (component) => component.name === "LineChart"
      )
        ? `
       private fun populateLineChart(values: Array<Int>) {
       val ourLineChartEntries: ArrayList<Entry> = ArrayList()

       var i = 0

       for (entry in values) {
           var value = values[i].toFloat()
           ourLineChartEntries.add(Entry(i.toFloat(), value))
           i++
       }
       val lineDataSet = LineDataSet(ourLineChartEntries, "")
       lineDataSet.setColors(*ColorTemplate.PASTEL_COLORS)
       val data = LineData(lineDataSet)

       binding.ourLineChart.axisLeft.setDrawGridLines(false)
       val xAxis: XAxis = binding.ourLineChart.xAxis
       xAxis.setDrawGridLines(false)
       xAxis.setDrawAxisLine(false)
       binding.ourLineChart.legend.isEnabled = false

       //remove description label
       binding.ourLineChart.description.isEnabled = false

       //add animation
       binding.ourLineChart.animateX(1000, Easing.EaseInSine)
       binding.ourLineChart.data = data
       //refresh
       binding.ourLineChart.invalidate()
   }
       `
        : ""
      }
   `;
  };


};
