using System;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor.VersionControl;
using UnityEngine;

namespace Unity.VisualScripting
{
    public static class VersionControlUtility
    {
        // Perforce and other VCS have a lock mechanism that usually
        // only makes the file writable once checked out. We need to
        // check them out before writing to them for auto-generated files.
        public static void Unlock(string path)
        {
            Ensure.That(nameof(path)).IsNotNull(path);

            UnityAPI.Await
                (
                    () =>
                    {
                        // The API changed in 2019, adding a third optional ChangeSet parameter
                        // which defaults to null but breaks the compiled signature below
                        // Furthermore, we can't even so much as have the call in the body of this method,
                        // or it will fail even if the if branch evaluates to false. So we

                        if (File.Exists(path) && Provider.enabled && Provider.isActive && Provider.hasCheckoutSupport)
                        {
                            try
                            {
                                var provider = typeof(Provider);

                                if (EditorApplicationUtility.unityVersion >= "2019.1.0")
                                {
                                    var method = provider.GetMethods()
                                        .FirstOrDefault
                                        (
                                            m => m.Name == "Checkout" &&
                                            m.GetParameters().Length == 3 &&
                                            m.GetParameters()[0].ParameterType == typeof(string) &&
                                            m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                        );

                                    if (method == null)
                                    {
                                        throw new MissingMemberException(provider.FullName, "Checkout");
                                    }

                                    method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both, null);
                                }
                                else
                                {
                                    var method = provider.GetMethods()
                                        .FirstOrDefault
                                        (
                                            m => m.Name == "Checkout" &&
                                            m.GetParameters().Length == 2 &&
                                            m.GetParameters()[0].ParameterType == typeof(string) &&
                                            m.GetParameters()[1].ParameterType == typeof(CheckoutMode)
                                        );

                                    if (method == null)
                                    {
                                        throw new MissingMemberException(provider.FullName, "Checkout");
                                    }

                                    method.InvokeOptimized(null, PathUtility.FromProject(path), CheckoutMode.Both);
                                }
                            }
                            catch (Exception ex)
                            {
                                Debug.LogWarning($"Failed to automatically checkout file from version control:\n{path}\n{ex}");
                            }
                        }

                        if (File.Exists(path))
                        {
                            var info = new FileInfo(path);

                            if (info.IsReadOnly)
                            {
                                var sb = new StringBuilder();
                                sb.AppendLine($"File '{info.Name}' is read-only despite attempted checkout. Manually forcing to writable.");
                                sb.AppendLine($"This may cause version control issues. Please report the following debug information:");
                                sb.AppendLine($"File Exists: {File.Exists(path)}");
                                sb.AppendLine($"Provider.enabled: {Provider.enabled}");
                                sb.AppendLine($"Provider.isActive: {Provider.isActive}");
                                sb.AppendLine($"Provider.hasCheckoutSupport: {Provider.hasCheckoutSupport}");
                                Debug.LogWarning(sb.ToString());

                                info.IsReadOnly = false;
                            }
                        }
                    }
                );
        }
    }
}