using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.Android;

using Platform101XP.Editor.Settings;

public class PostBuildGradle : IPostGenerateGradleAndroidProject
{
    public int callbackOrder => 999;

    public void OnPostGenerateGradleAndroidProject(string path)
    {
        // Normalize paths
        string unityLibraryPath = Path.GetFullPath(path);
        string projectRootPath = Path.Combine(unityLibraryPath, "..");
        string launcherPath = Path.Combine(projectRootPath, "launcher");

        // Define paths to Gradle build files
        string projectBuildGradle = Path.Combine(projectRootPath, "build.gradle");
        string launcherBuildGradle = Path.Combine(launcherPath, "build.gradle");
        string unityLibraryBuildGradle = Path.Combine(unityLibraryPath, "build.gradle");
        string settingsGradlePath = Path.Combine(projectRootPath, "settings.gradle");

        // Define paths to additional Gradle scripts inside Unity project
        string gradleScriptsPath = Path.Combine(Application.dataPath, "Platform101XP", "Templates", "Gradle");
        string baseGradleScript = Path.Combine(gradleScriptsPath, "base_build_addition.gradle");
        string launchGradleScript = Path.Combine(gradleScriptsPath, "launch_build_addition.gradle");
        string mainGradleScript = Path.Combine(gradleScriptsPath, "main_build_addition.gradle");
        string additionalRepositoriesPath = Path.Combine(gradleScriptsPath, "settings_additional.gradle");

        try
        {
            UpdateGradleProperties(path);
            PrependGradleContents(projectBuildGradle, baseGradleScript);
            AppendGradleContents(launcherBuildGradle, launchGradleScript);
            AppendGradleContents(unityLibraryBuildGradle, mainGradleScript);
            InsertRepositoriesBeforeLastFlatDir(settingsGradlePath, additionalRepositoriesPath);
            Debug.Log("Android project modifications applied successfully.");
        }
        catch (Exception ex)
        {
            Debug.LogError("Error modifying Android project: " + ex.Message + "\n" + ex.StackTrace);
            throw;
        }
    }

    private void UpdateGradleProperties(string path)
    {
        string gradlePropertiesFile = Path.Combine(path, "../gradle.properties");
        if (!File.Exists(gradlePropertiesFile))
        {
            var message = "Gradle properties file does not exist: " + gradlePropertiesFile;
            Debug.LogError(message);
            throw new Exception(message);
        }

        // Prepare properties 
        Dictionary<string, string> properties = new();
        properties["android.useAndroidX"] = "true";
        properties["android.enableJetifier"] = "true";
        properties["android.nonTransitiveRClass"] = "false";
        properties["android.nonFinalResIds"] = "false";
        properties["android.enableR8.fullMode"] = "false";
        properties["android.suppressUnsupportedCompileSdk"] = "37.0";
        properties["yandex.client.id"] = SettingsManager.Instance.Android.YandexClientId;
        properties["vkid.enabled"] = SettingsManager.Instance.Android.VkEnabled.ToString().ToLowerInvariant();
        properties["vkid.client.id"] = SettingsManager.Instance.Android.VkEnabled
            ? SettingsManager.Instance.Android.VkClientId
            : string.Empty;
        properties["vkid.client.secret"] = SettingsManager.Instance.Android.VkEnabled
            ? SettingsManager.Instance.Android.VkClientSecret
            : string.Empty;
        properties["cloudpayments.enabled"] =
            SettingsManager.Instance.Android.BillingCloudPaymentsEnabled.ToString().ToLowerInvariant();

        // Update/Add properties
        var lines = File.ReadAllLines(gradlePropertiesFile).ToList();
        lines.RemoveAll(line => line.StartsWith(
            "android.defaults.buildfeatures.buildconfig=",
            StringComparison.Ordinal
        ));
        lines.RemoveAll(line => line.StartsWith(
            "android.builtInKotlin=",
            StringComparison.Ordinal
        ));
        var linesToAdd = new List<string>();
        foreach (var property in properties)
        {
            var propertyString = $"{property.Key}={property.Value}";
            var updated = false;
            for (int i = 0; i < lines.Count; i++)
            {
                if (lines[i].StartsWith($"{property.Key}=", StringComparison.Ordinal))
                {
                    lines[i] = propertyString;
                    updated = true;
                    break;
                }
            }

            if (!updated)
            {
                linesToAdd.Add(propertyString);
            }
        }

        lines.AddRange(linesToAdd);
        File.WriteAllLines(gradlePropertiesFile, lines);
        Debug.Log("Gradle properties file is updated.");
    }

    private void PrependGradleContents(string buildGradlePath, string additionGradlePath)
    {
        string additionalContent = File.ReadAllText(additionGradlePath);
        string originalContent = File.ReadAllText(buildGradlePath);

        if (originalContent.Contains(additionalContent))
        {
            Debug.Log($"Prepend content in the {additionGradlePath} file is already exist, skipping modification.");
            return;
        }

        string newContent = additionalContent + "\n" + originalContent;
        File.WriteAllText(buildGradlePath, newContent);
        Debug.Log($"Prepended contents of {additionGradlePath} to {buildGradlePath}");
    }

    private void AppendGradleContents(string buildGradlePath, string additionGradlePath)
    {
        string additionalContent = File.ReadAllText(additionGradlePath);
        string originalContent = File.ReadAllText(buildGradlePath);

        if (originalContent.Contains(additionalContent))
        {
            Debug.Log($"Append content in the {additionGradlePath} file is already exist, skipping modification.");
            return;
        }

        File.AppendAllText(buildGradlePath, "\n" + additionalContent);
        Debug.Log($"Appended contents of {additionGradlePath} to {buildGradlePath}");
    }

    private void InsertRepositoriesBeforeLastFlatDir(string settingsGradlePath, string additionalRepositoriesPath)
    {
        string originalContent = File.ReadAllText(settingsGradlePath);
        string additionalRepositories = File.ReadAllText(additionalRepositoriesPath);
        if (originalContent.Contains(additionalRepositories))
        {
            Debug.LogWarning("Additional repositories already exist, skipping modification.");
            return;
        }

        string[] lines = File.ReadAllLines(settingsGradlePath);
        int lastFlatDirIndex = -1;

        // Find the last occurrence of "flatDir"
        for (int i = lines.Length - 1; i >= 0; i--)
        {
            if (lines[i].Contains("flatDir"))
            {
                lastFlatDirIndex = i;
                break;
            }
        }

        if (lastFlatDirIndex == -1)
        {
            Debug.LogError("Failed to locate 'flatDir' in settings.gradle. Modification aborted.");
            throw new System.Exception("settings.gradle structure mismatch: 'flatDir' not found.");
        }

        // Insert the new repositories before the last "flatDir" line
        var updatedLines = new List<string>(lines);
        updatedLines.Insert(lastFlatDirIndex, additionalRepositories);

        File.WriteAllLines(settingsGradlePath, updatedLines);
        Debug.Log("Extra repositories inserted successfully before the last 'flatDir'.");
    }
}
