using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using Google.Apis.Sheets.v4;
using Google.Apis.Util.Store;
using UnityEngine;

#region Editor
#if UNITY_EDITOR
using UnityEditor;

public static partial class DialogueDatabase
{
    
    public static string EDITOR_DialogueFile =>
        Path.Combine(Application.dataPath, "Data", "Dialogue", DIALOGUE_FILENAME);
    
    // TODO: neither of these should be in the repository! ideally, move them behind secure
    // gitlab variables before there is too much data at risk
    private const string SPREADSHEET_ID = "1H42653xGbKLxbsDzz7CSR0iaNMz1hU42LX5hWiFtn-Y";
    private const string API_KEY = "AIzaSyD-tKzeKpAj5sFnbXbj2k4H2RQxipw8B8s";
    private const string SERVICE_ACCOUNT_EMAIL = "gitlab-runner-dialogue-import@revival-304616.iam.gserviceaccount.com";
    private const string CERTIFICATE_NAME = "revival-304616-7f150d13c408.p12";
    
    private static string _workFolder => Path.Combine(Application.dataPath, "Data", "Dialogue");
    private static string _certificateFile => Path.Combine(_workFolder, CERTIFICATE_NAME);

    // makes a web request via google 
    // returns 0 on success
    public static int Import()
    {
        var certificate = new X509Certificate2(_certificateFile, "notasecret", X509KeyStorageFlags.Exportable);

        var credential = new ServiceAccountCredential(
            new ServiceAccountCredential.Initializer(SERVICE_ACCOUNT_EMAIL)
            {
                Scopes = new[] {SheetsService.Scope.SpreadsheetsReadonly}
            }.FromCertificate(certificate));

        var service = new SheetsService(new BaseClientService.Initializer()
        {
            HttpClientInitializer = credential,
            ApplicationName = "Kernel Panic - Revival Dialogue Importer",
            ApiKey = API_KEY
        });

        // first two columns, ignore first row
        var range = "Sheet1!A2:B";
        var request = service.Spreadsheets.Values.Get(SPREADSHEET_ID, range);

        var response = request.Execute();
        var values = response.Values;

        if (values == null || values.Count == 0)
        {
            Debug.LogError("no data");
            return 1;
        }

        Debug.Log($":: importing dialogue");
        var sb = new StringBuilder();
        var lines = 0;
        foreach (var row in values)
        {
            if (row.Count != 2)
            {
                Debug.Log($":: skipping non-matching line: {lines}: {(row.Count == 0 ? "empty" : string.Join(",", row))}");
                continue;
            }
            
            sb.AppendLine($"{row[0]}{SPLIT_CHAR}{row[1]}");
            lines++;
        }
        Debug.Log($":: imported {lines} lines of dialogue\n{sb}");

        File.WriteAllText(EDITOR_DialogueFile, sb.ToString());
        if (!File.Exists(EDITOR_DialogueFile))
        {
            Debug.LogError($":: import failed: file doesn't exist: {EDITOR_DialogueFile}");
            return 1;
        }

        return 0;
    }

    [MenuItem("ktyl/Import Dialogue")]
    private static void ImportDialogueMenuItem()
    {
        Import();
    }
}

#endif
#endregion

public static partial class DialogueDatabase
{
    private const char SPLIT_CHAR = '|';
    
    public const string DIALOGUE_FILENAME = "dialogue.data";

    public static string DialogueFile
    {
        get
        {
#if UNITY_EDITOR
            // ensure file exists and run import if necessary
            if (!File.Exists(EDITOR_DialogueFile) && Import() != 0) return null;
            
            return EDITOR_DialogueFile;
#else
            return Path.Combine(Application.dataPath, DIALOGUE_FILENAME);
#endif
        }
    }

    static DialogueDatabase()
    {
        Debug.Log($":: building dialogue database from file at {DialogueFile}");

        int count = 0;
        foreach (var line in File.ReadLines(DialogueFile))
        {
            var parts = line.Split(SPLIT_CHAR);

            var key = parts[0];
            var text = parts[1];
            if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(text))
            {
                Debug.LogWarning($"bad line in csv: {line}");
                continue;
            }

            _dict[key] = text;
            count++;
        }

        Debug.Log($":: imported {count} lines of dialogue");
    }

    private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();

    public static string[] Keys => _dict.Keys.ToArray();

    public static string ReadDialogue(string key)
    {
        return _dict.ContainsKey(key)
            ? _dict[key]
            : $"<color=\"red\">MISSING[{key}]</color>";
    }
}