using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using Debug = UnityEngine.Debug;

namespace LLM.Editor.PoC
{
    /// <summary>
    /// A Unity Editor Window to interact with Google Cloud's Gemini LLM.
    /// This tool authenticates using the gcloud CLI to get an OAuth 2.0 token.
    /// </summary>
    public class LLMPromptTool : EditorWindow
    {
        // --- PRIVATE FIELDS ---

        // User inputs
        private string _gcpProjectId = "your-gcp-project-id";
        private string _region = "us-central1";
        private string _modelName = "gemini-1.5-flash-preview-0514";
        private string _gcloudPath = "gcloud"; // Path to the gcloud executable
        private string _promptText = "Please explain what this C# script does.";
        private string _filePath = "";
        private string _fileContent = "";

        // Response and status
        private string _llmResponse = "Awaiting prompt...";
        private bool _isRequestInProgress;

        // UI layout
        private Vector2 _promptScrollPos;
        private Vector2 _responseScrollPos;

        // --- UNITY EDITOR WINDOW ---

        [MenuItem("LLM/LLM Prompt Tool")]
        public static void ShowWindow()
        {
            GetWindow<LLMPromptTool>("GCP LLM Prompt");
        }

        void OnGUI()
        {
            var titleStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 16, alignment = TextAnchor.MiddleCenter };
            var headerStyle = new GUIStyle(EditorStyles.boldLabel) { fontSize = 12 };
            var wordWrapLabelStyle = new GUIStyle(EditorStyles.label) { wordWrap = true };
            var wordWrapTextAreaStyle = new GUIStyle(EditorStyles.textArea) { wordWrap = true };

            EditorGUILayout.LabelField("GCP LLM Prototype", titleStyle, GUILayout.Height(25));
            EditorGUILayout.Space(10);

            EditorGUILayout.LabelField("GCP Configuration", headerStyle);
            _gcpProjectId = EditorGUILayout.TextField("Project ID", _gcpProjectId);
            _region = EditorGUILayout.TextField("Region", _region);
            _modelName = EditorGUILayout.TextField("Model Name", _modelName);
            _gcloudPath = EditorGUILayout.TextField("GCloud Executable Path", _gcloudPath);
            EditorGUILayout.HelpBox("Because Unity doesn't know your system's PATH, you may need to provide the full path to the gcloud executable.\n- On macOS/Linux, run 'which gcloud' in terminal.\n- On Windows, run 'where gcloud' in Command Prompt.", MessageType.Info);

            EditorGUILayout.Space(15);

            EditorGUILayout.LabelField("User Prompt", headerStyle);
            _promptScrollPos = EditorGUILayout.BeginScrollView(_promptScrollPos, GUILayout.Height(100));
            _promptText = EditorGUILayout.TextArea(_promptText, wordWrapTextAreaStyle, GUILayout.ExpandHeight(true));
            EditorGUILayout.EndScrollView();

            EditorGUILayout.Space(10);

            EditorGUILayout.LabelField("Attach C# File (Optional)", headerStyle);
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.TextField("File Path", _filePath);
            if (GUILayout.Button("Browse...", GUILayout.Width(80)))
            {
                SelectFile();
            }
            EditorGUILayout.EndHorizontal();

            if (!string.IsNullOrEmpty(_fileContent))
            {
                EditorGUILayout.HelpBox($"Attached file '{Path.GetFileName(_filePath)}'. Length: {_fileContent.Length} characters.", MessageType.None);
            }

            EditorGUILayout.Space(15);

            UnityEngine.GUI.enabled = !_isRequestInProgress && !string.IsNullOrEmpty(_gcpProjectId);
            if (GUILayout.Button(_isRequestInProgress ? "Waiting for Response..." : "Send Prompt to Gemini", GUILayout.Height(40)))
            {
                _ = SendPromptToLLM();
            }
            UnityEngine.GUI.enabled = true;

            EditorGUILayout.Space(15);

            EditorGUILayout.LabelField("LLM Response", headerStyle);
            _responseScrollPos = EditorGUILayout.BeginScrollView(_responseScrollPos, EditorStyles.helpBox, GUILayout.ExpandHeight(true));
            EditorGUILayout.SelectableLabel(_llmResponse, wordWrapLabelStyle, GUILayout.ExpandHeight(true));
            EditorGUILayout.EndScrollView();
        }

        // --- PRIVATE METHODS ---

        /// <summary>
        /// Executes the 'gcloud auth print-access-token' command to get a valid OAuth 2.0 token.
        /// </summary>
        /// <returns>The access token string, or null if an error occurs.</returns>
        private string GetAccessToken()
        {
            try
            {
                var startInfo = new ProcessStartInfo
                {
                    FileName = _gcloudPath, // Use the full path provided by the user
                    Arguments = "auth print-access-token",
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                };

                using var process = Process.Start(startInfo);
                if (process != null)
                {
                    var accessToken = process.StandardOutput.ReadToEnd().Trim();
                    var error = process.StandardError.ReadToEnd();
                    process.WaitForExit();

                    if (process.ExitCode == 0) return accessToken;
                    Debug.LogError($"gcloud error: {error}");
                    _llmResponse = $"Failed to get auth token. Is gcloud CLI installed and are you logged in?\nError: {error}";
                    return null;
                }
            }
            catch (System.Exception e)
            {
                Debug.LogError($"Exception while getting access token: {e.Message}");
                _llmResponse = $"Failed to run gcloud from path '{_gcloudPath}'. Ensure the path is correct and the Google Cloud CLI is installed.";
            }
            return null;
        }

        private void SelectFile()
        {
            var path = EditorUtility.OpenFilePanel("Select C# Script", Application.dataPath, "cs");
            if (string.IsNullOrEmpty(path)) return;
            _filePath = path;
            try
            {
                _fileContent = File.ReadAllText(_filePath);
            }
            catch (System.Exception e)
            {
                _fileContent = "";
                _filePath = "";
                Debug.LogError($"Failed to read file: {e.Message}");
                _llmResponse = $"Error: Could not read file at path {path}.";
            }
        }

        private async Task SendPromptToLLM()
        {
            _isRequestInProgress = true;
            _llmResponse = "Getting auth token...";
            Repaint();

            // 1. Get the OAuth 2.0 access token from gcloud
            var accessToken = GetAccessToken();
            if (string.IsNullOrEmpty(accessToken))
            {
                _isRequestInProgress = false;
                Repaint();
                return;
            }

            _llmResponse = "Sending request to GCP...";
            Repaint();

            // 2. Construct the API request
            var url = $"https://{_region}-aiplatform.googleapis.com/v1/projects/{_gcpProjectId}/locations/{_region}/publishers/google/models/{_modelName}:generateContent";
            var requestPayload = new RequestPayload();
            var fullPrompt = new StringBuilder(_promptText);

            if (!string.IsNullOrEmpty(_fileContent))
            {
                fullPrompt.AppendLine("\n\n--- Attached C# Script ---");
                fullPrompt.AppendLine(_fileContent);
            }
        
            requestPayload.contents[0].parts[0].text = fullPrompt.ToString();
            requestPayload.contents[0].role = "user";
            var jsonPayload = JsonUtility.ToJson(requestPayload);

            // 3. Send the request with the new auth token
            using (var request = new UnityWebRequest(url, "POST"))
            {
                var bodyRaw = Encoding.UTF8.GetBytes(jsonPayload);
                request.uploadHandler = new UploadHandlerRaw(bodyRaw);
                request.downloadHandler = new DownloadHandlerBuffer();
                request.SetRequestHeader("Content-Type", "application/json");
                request.SetRequestHeader("Authorization", $"Bearer {accessToken}"); // Use the fetched token

                var operation = request.SendWebRequest();
                while (!operation.isDone)
                {
                    await Task.Yield();
                }

                if (request.result == UnityWebRequest.Result.Success)
                {
                    try
                    {
                        var responseJson = request.downloadHandler.text;
                        var responsePayload = JsonUtility.FromJson<ResponsePayload>(responseJson);
                    
                        if (responsePayload.candidates != null && responsePayload.candidates.Length > 0 && responsePayload.candidates[0].content?.parts?.Length > 0)
                        {
                            _llmResponse = responsePayload.candidates[0].content.parts[0].text;
                            Debug.Log(_llmResponse);
                        }
                        else
                        {
                            _llmResponse = "Received a valid but empty or malformed response.\n\n" + responseJson;
                        }
                    }
                    catch (System.Exception e)
                    {
                        _llmResponse = $"Failed to parse JSON response: {e.Message}\n\nRaw Response:\n{request.downloadHandler.text}";
                    }
                }
                else
                {
                    _llmResponse = $"Error: {request.error}\n\n{request.downloadHandler.text}";
                    Debug.LogError($"GCP Request Error: {request.error}\nResponse: {request.downloadHandler.text}");
                }
            }

            _isRequestInProgress = false;
            Repaint();
        }

        // --- JSON HELPER CLASSES ---

        [System.Serializable] private class RequestPayload { public Content[] contents = { new() }; }
        [System.Serializable] private class Content { public Part[] parts = { new() }; public string role; }
        [System.Serializable] private class Part { public string text; }
        [System.Serializable] private class ResponsePayload { public Candidate[] candidates; }
        [System.Serializable] private class Candidate { public Content content; }
    }
}