using System;
using System.Collections.Generic;
using System.Linq;
using Nest;
using Newtonsoft.Json; //Do not remove - Required for JObject
using Newtonsoft.Json.Linq; //Do not remove - Required for JObject
using Shinydocs.CognitiveToolkit.Scripting;
using Shinydocs.CognitiveToolkit.Utilities;
using IScript = Shinydocs.CognitiveToolkit.Scripting.IScript;

public class UpdateIndexMapping : IScript
{
	private static string Version = "2.6.0";
    private const string Update = @"
             _   _           _       _      _____          _          ___  ___                  _             
            | | | |         | |     | |    |_   _|        | |         |  \/  |                 (_)            
            | | | |_ __   __| | __ _| |_ ___ | | _ __   __| | _____  _| .  . | __ _ _ __  _ __  _ _ __   __ _ 
            | | | | '_ \ / _` |/ _` | __/ _ \| || '_ \ / _` |/ _ \ \/ / |\/| |/ _` | '_ \| '_ \| | '_ \ / _` |
            | |_| | |_) | (_| | (_| | ||  __/| || | | | (_| |  __/>  <| |  | | (_| | |_) | |_) | | | | | (_| |
            \___/| .__/ \__,_|\__,_|\__\___\___/_| |_|\__,_|\___/_/\_\_|  |_/\__,_| .__/| .__/|_|_| |_|\__, |
                 | |                                                              | |   | |             __/ |
                 |_|                                                              |_|   |_|            |___/ 
        ";
    
    private readonly ScriptLogger _log = new ScriptLogger();

    private string _indexName;
    private string _serverUrl;

    public void SetUp(string[] arguments)
    {
		_log.Information(string.Format("Using version {0}", Version));
		Console.WriteLine(string.Format("Using version {0}", Version));
        try
        {
            Dictionary<string, string> options;
            // OptionsParser will parse an array of arguments into a dictionary of flags and values
            if (OptionsParser.TryParse(arguments, out options))
            {
                _serverUrl = options["-u"];
                _indexName = options["-i"];
            }
            else
            {
                throw new ArgumentException("Failed to parse arguments");
            }
        }
        catch (Exception)
        {
            Console.WriteLine("Server Url (-u) and Index Name (-i) are required fields.");
            throw;
        }
    }

    public void Run()
    {
        
        
        var connection = new ConnectionSettings(new Uri(_serverUrl));
        connection.DisableDirectStreaming(false);

        Console.WriteLine("Connecting to " + _serverUrl + " ...");
        var client = new ElasticClient(connection);
        
        Console.WriteLine("Updating dynamic templates ...");
        var dynamicResponse = client.Map<dynamic>(
            m => m
                .Index(_indexName)
                .Type("shinydocs")
                .DynamicTemplates(
                    dts => dts
                        .DynamicTemplate(
                            "custom-columns",
                            dt => dt
                                .Match("cc-*")
                                .Mapping(
                                    cc => cc
                                        .Text(
                                            t => t
                                                .Fields(
                                                    f => f
                                                        .Keyword(
                                                            k => k
                                                                .Name("keyword")
                                                                .IgnoreAbove(256))))))
                        .DynamicTemplate(
                            "filenet-props",
                            dt => dt
                                .Match("prop-*")
                                .Mapping(
                                    prop => prop
                                        .Text(
                                            t => t
                                                .Fields(
                                                    f => f
                                                        .Keyword(
                                                            k => k
                                                                .Name("keyword")
                                                                .IgnoreAbove(256)))))
                        )
                )
        );


        if (!dynamicResponse.IsValid)
        {
            Console.WriteLine("Error occurred. Please check the logs for more details.");
            _log.Error(dynamicResponse.DebugInformation);
        }
        else
        {
            Console.WriteLine("Dynamic Templates Complete!");
        }

        Console.WriteLine("Collecting field information from " + _indexName + " ...");
        var mappingsResponse = client.GetMapping<dynamic>(map => map.Index(_indexName).Type(Types.AllTypes));
        var customTypes = mappingsResponse.Indices[_indexName].Mappings["shinydocs"].Properties
            .Where(m => m.Key.Name.StartsWith("cc-") || m.Key.Name.StartsWith("prop-"));

        var updated = 0;
        var skipped = 0;
        var updatePropResponse = client.Map<dynamic>(
            m => m
                .Index(_indexName)
                .Type("shinydocs")
                .Properties(
                    p =>
                    {
                        foreach (var property in customTypes)
                        {
                            var name = property.Key.Name;
                            if (property.Value.Type == "text")
                            {
                                p.Text(
                                    t => t
                                        .Name(name)
                                        .Fields(
                                            f => f
                                                .Keyword(
                                                    k => k
                                                        .IgnoreAbove(256)
                                                        .Name("keyword")
                                                )
                                        )
                                );
                                updated++;
                            }
                            else
                            {
                                skipped++;
                                _log.Warning("Skipping '" + name + "'. " + property.Value.Type + " is not a text type.");
                            }
                        }

                        return p;
                    })
        );
        
        if (!updatePropResponse.IsValid)
        {
            Console.WriteLine("Error occurred. Please check the logs for more details.");
            _log.Error(updatePropResponse.DebugInformation);
        }
        else
        {
            Console.WriteLine("Field Mapping Complete! Updated {0} fields. Skipped {1} fields.", updated, skipped);
            if (skipped > 0)
            {
                Console.WriteLine("Check the log for skipped fields.");
            }
        }
    }


    public void TearDown()
    {
    }
}