using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using FarmmapsApi;
using FarmmapsApi.Models;
using FarmmapsApi.Services;
using FarmmapsHaulmkilling.Models;
using FarmmapsZonering.Models;
using FarmmapsZonering.Services;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using static FarmmapsApiSamples.Constants;

namespace FarmmapsZonering
{
    public class ZoneringApplication : IApplication
    {
        private const string DownloadFolder = "Downloads";
        private const string SettingsFile = "settings.json";

        private readonly ILogger<ZoneringApplication> _logger;
        private readonly FarmmapsApiService _farmmapsApiService;
        private readonly GeneralService _generalService;
        private readonly ZoneringService _zoneringService;

        private Settings _settings;
        
        public ZoneringApplication(ILogger<ZoneringApplication> logger, FarmmapsApiService farmmapsApiService,
            GeneralService generalService, ZoneringService zoneringService)
        {
            _logger = logger;
            _farmmapsApiService = farmmapsApiService;
            _generalService = generalService;
            _zoneringService = zoneringService;
        }
        
        public async Task RunAsync()
        {
            if (!Directory.Exists(DownloadFolder))
                Directory.CreateDirectory(DownloadFolder);

            // Read input data from separate file
            var zoneringInputJson = File.ReadAllText("ZoneringInput.json");
            List<ZoneringInput> zoneringInputs = JsonConvert.DeserializeObject<List<ZoneringInput>>(zoneringInputJson);
            
            // !! this call is needed the first time an api is called with a fresh clientid and secret !!
            await _farmmapsApiService.GetCurrentUserCodeAsync();
            var roots = await _farmmapsApiService.GetCurrentUserRootsAsync();
            
            
            foreach (var input in zoneringInputs)
            {
                try
                {
                    await ZoningAsync(roots, input);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.Message);
                }
            }

        }
        
        private async Task ZoningAsync(List<UserRoot> roots, ZoneringInput input)
        {
            var myDrive = roots.SingleOrDefault(r => r.Name == "USER_FILES");
            if (myDrive == null)
            {
                _logger.LogError("Could not find a needed root item");
                return;
            }

            bool useCreatedCropfield = false;
            bool GetWatBal = input.GetWatBal;
            bool getVanDerSat = input.GetVanDerSat;
            bool StoreVanDerSatStatistics = input.storeVanDerSatStatistics;
            var FieldName = input.CropFieldName;
            string settingsfile = $"Settings_{FieldName}.json";

            // Load settings from previous cropfield
            LoadSettings(settingsfile);

            var uploadedRoot = roots.SingleOrDefault(r => r.Name == "USER_IN");
            if (uploadedRoot == null)
            {
                _logger.LogError("Could not find a needed root item");
                return;
            }

            Item cropfieldItem;
            if (input.CreateNewCropfield == true) // ||  string.IsNullOrEmpty(_settings.CropfieldItemCode) ## CHECK IT!!
            {
                _logger.LogInformation("Creating cropfield");


                cropfieldItem = await _generalService.CreateCropfieldItemAsync(myDrive.Code, input.CropFieldName, input.CropYear,
                input.GeometryJson.ToString(Formatting.None));
                
                _settings.CropfieldName = cropfieldItem.Name;
                _settings.CropfieldItemCode = cropfieldItem.Code;
                SaveSettings(settingsfile);

            }            
            else
            {
                _logger.LogInformation("Cropfield already exists trying to get");
                cropfieldItem = await _farmmapsApiService.GetItemAsync(_settings.CropfieldItemCode);
            }
            
            if (GetWatBal==true) {
            ////Run watbal
            //if (useCreatedCropfield == false || string.IsNullOrEmpty(_settings.WatBalTaskCode)) {
            //    var WatBalTaskCode = await _generalService.RunWatBalTask(cropfieldItem);
            //    _settings.WatBalTaskCode = WatBalTaskCode;
            //    SaveSettings(settingsfile);
            //}

            //// Get watbal data
            //Item WatBalItem = await _generalService.FindWatBalItem(cropfieldItem, _settings.WatBalTaskCode, FieldName, StoreStatistics);
            }

            if (getVanDerSat==true) {
            // check if vandersat task not yet done, do here and save taskcode
                if (useCreatedCropfield == false || string.IsNullOrEmpty(_settings.VanDerSatTaskCode)) {
                    var VanDerSatTaskCode = await _generalService.RunVanDerSatTask(cropfieldItem);
                    _settings.VanDerSatTaskCode = VanDerSatTaskCode;
                    SaveSettings(settingsfile);
                }

                // Select a particular image item from VanDerSat
                Item VanDerSatItem = await _generalService.FindVanDerSatItem(cropfieldItem, _settings.VanDerSatTaskCode, FieldName, StoreVanDerSatStatistics);


                // download the geotiff
                _logger.LogInformation("Downloading geotiff file");
                await _farmmapsApiService.DownloadItemAsync(VanDerSatItem.Code,
                    Path.Combine(DownloadFolder, $"nbs_VanDerSatGeotiff_{input.OutputFileName}.zip"));
            }

            var inputOneItem = await _generalService.UploadDataAsync(uploadedRoot, GEOTIFF_PROCESSED_ITEMTYPE,
            Path.Combine("Data", $"{input.InputItemOne}"), Path.GetFileNameWithoutExtension($"{input.InputItemOne}"));

            if (inputOneItem == null)
            {
                _logger.LogError("Could not find item for uploaded data");
                return;
            }


            //var inputTwoItem = await _generalService.UploadDataAsync(uploadedRoot, GEOTIFF_PROCESSED_ITEMTYPE,
            //    Path.Combine("Data", $"{input.InputItemTwo}"), Path.GetFileNameWithoutExtension($"{input.InputItemTwo}"));

            //if (inputTwoItem == null) {
            //    _logger.LogError("Could not find item for uploaded data");
            //    return;
            //}

            var outputItem = await _zoneringService.CreateApplicationMapAsync(cropfieldItem, input.Formula, new Output()
                {
                    Name = input.CalculatedLayerName,
                    Quantity = input.CalculatedQuantity,
                    Unit = input.CalculatedUnit,
                 

                }, new InputParameter()
                {
                    ItemCode = inputOneItem.Code,
                    LayerName = inputOneItem.Data["layers"][0]["name"].ToString()
                //},
                //new InputParameter()
                //{
                //    ItemCode = inputTwoItem.Code,
                //    LayerName = inputTwoItem.Data["layers"][0]["name"].ToString()
                });
            
            _logger.LogInformation("Downloading output");
            _logger.LogInformation($"outputitem: {outputItem} with code {outputItem.Code} and date {outputItem.DataDate}");
                       
            await _farmmapsApiService.DownloadItemAsync(outputItem.Code,

                Path.Combine(DownloadFolder, $"{input.OutputFileName}.zoning.zip"));

        }

        // Functions to save previously created cropfields
        private void LoadSettings(string file) {
            if (File.Exists(file)) {
                var jsonText = File.ReadAllText(file);
                _settings = JsonConvert.DeserializeObject<Settings>(jsonText);
            } else {
                _settings = new Settings();
            }
        }

        private void SaveSettings(string file) {
            if (_settings == null)
                return;

            var json = JsonConvert.SerializeObject(_settings);
            File.WriteAllText(file, json);
        }
        private void SaveInfo(string file) {
            if (_settings == null)
                return;

            var json = JsonConvert.SerializeObject(_settings);
            File.WriteAllText(file, json);
        }
        }
}