using System;
using System.Drawing;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
using Microsoft.Office.Core;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace OutlookAddin.Ribbon
{
    /// <summary>
    /// Single <see cref="IRibbonExtensibility"/> implementation that serves
    /// both the Explorer ribbon (Inbox / list view) and the Inspector ribbon
    /// (compose window) — VSTO calls <see cref="GetCustomUI"/> with a
    /// ribbonID identifying which host is asking.
    /// </summary>
    [ComVisible(true)]
    public class ExplorerRibbon : IRibbonExtensibility
    {
        private const string ExplorerResource = "OutlookAddin.Ribbon.ExplorerRibbon.xml";
        private const string InspectorResource = "OutlookAddin.Ribbon.InspectorRibbon.xml";

        // Every button whose `getEnabled` depends on the current Explorer
        // selection must be re-evaluated on every SelectionChange — Office
        // caches the initial result otherwise and the button stays stuck.
        private static readonly string[] SelectionDependentButtons =
        {
            "FileToEspoCrm",
            "SaveAttachments"
        };

        private IRibbonUI? _explorerRibbon;
        private IRibbonUI? _inspectorRibbon;

        public string GetCustomUI(string ribbonID)
        {
            switch (ribbonID)
            {
                case "Microsoft.Outlook.Explorer":
                    return LoadResource(ExplorerResource);
                case "Microsoft.Outlook.Mail.Compose":
                    return LoadResource(InspectorResource);
                default:
                    return string.Empty;
            }
        }

        public void OnRibbonLoad(IRibbonUI ribbon)
        {
            _explorerRibbon = ribbon;
            try
            {
                var explorer = Globals.ThisAddIn.Application.ActiveExplorer();
                if (explorer != null)
                {
                    explorer.SelectionChange += InvalidateSelectionDependentButtons;
                }
            }
            catch
            {
                // Explorer may not be available during early load — ignore.
            }
        }

        private void InvalidateSelectionDependentButtons()
        {
            var ribbon = _explorerRibbon;
            if (ribbon == null) return;
            foreach (var id in SelectionDependentButtons)
            {
                try { ribbon.InvalidateControl(id); } catch { /* ignore */ }
            }
        }

        public void OnInspectorRibbonLoad(IRibbonUI ribbon)
        {
            _inspectorRibbon = ribbon;
        }

        public bool OnGetFileToEspoCrmEnabled(IRibbonControl control)
        {
            try
            {
                var selection = Globals.ThisAddIn.Application.ActiveExplorer()?.Selection;
                if (selection == null || selection.Count == 0) return false;
                for (int i = 1; i <= selection.Count; i++)
                {
                    if (selection[i] is Outlook.MailItem) return true;
                }
                return false;
            }
            catch
            {
                return false;
            }
        }

        public void OnFileToEspoCrm(IRibbonControl control)
        {
            _ = Globals.ThisAddIn.AddInHost.LaunchFileToCaseAsync();
        }

        public void OnOpenSettings(IRibbonControl control)
        {
            Globals.ThisAddIn.AddInHost.LaunchSettings();
        }

        public void OnShowSidebar(IRibbonControl control)
        {
            Globals.ThisAddIn.AddInHost.ShowSidebar();
        }

        public bool OnGetSaveAttachmentsEnabled(IRibbonControl control)
        {
            // Enabled only when EXACTLY one MailItem is selected AND it has
            // at least one attachment. Doing multi-mail save would conflict
            // with the per-file checkbox UX in the dialog.
            try
            {
                var selection = Globals.ThisAddIn.Application.ActiveExplorer()?.Selection;
                if (selection == null || selection.Count != 1) return false;
                if (selection[1] is not Outlook.MailItem mail) return false;
                var attachments = mail.Attachments;
                if (attachments == null) return false;
                return attachments.Count > 0;
            }
            catch
            {
                return false;
            }
        }

        public void OnSaveAttachments(IRibbonControl control)
        {
            try
            {
                var selection = Globals.ThisAddIn.Application.ActiveExplorer()?.Selection;
                if (selection == null || selection.Count != 1) return;
                if (selection[1] is Outlook.MailItem mail)
                {
                    _ = Globals.ThisAddIn.AddInHost.LaunchSaveAttachmentsAsync(mail);
                }
            }
            catch (Exception ex)
            {
                Globals.ThisAddIn.AddInHost.Logger.Warning(ex, "OnSaveAttachments failed");
            }
        }

        public bool OnGetComposeFromCaseVisible(IRibbonControl control)
        {
            // Show only on outgoing (compose) mail inspectors.
            try
            {
                var inspector = control?.Context as Outlook.Inspector;
                if (inspector?.CurrentItem is Outlook.MailItem mail)
                {
                    return mail.Sent == false;
                }
            }
            catch { /* fall through */ }
            return true;
        }

        public void OnComposeFromCase(IRibbonControl control)
        {
            try
            {
                var inspector = control?.Context as Outlook.Inspector;
                if (inspector?.CurrentItem is Outlook.MailItem mail)
                {
                    _ = Globals.ThisAddIn.AddInHost.LaunchComposeFromCaseAsync(mail);
                }
            }
            catch (Exception ex)
            {
                Globals.ThisAddIn.AddInHost.Logger.Warning(ex, "OnComposeFromCase failed");
            }
        }

        private static string LoadResource(string name)
        {
            using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name))
            {
                if (stream == null) return string.Empty;
                using (var reader = new StreamReader(stream))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// Per-button image callback. Office calls this once per ribbon
        /// button that has getImage="OnGetImage" and we map control.Id to
        /// the embedded PNG resource. Returning null falls back to
        /// "no icon" (text-only) rather than throwing.
        /// </summary>
        public Bitmap? OnGetImage(IRibbonControl control)
        {
            try
            {
                if (control == null) return null;
                string fileName;
                switch (control.Id)
                {
                    case "FileToEspoCrm":        fileName = "klear-file.png";     break;
                    case "SaveAttachments":      fileName = "klear-attach.png";   break;
                    case "ShowSidebar":          fileName = "klear-sidebar.png";  break;
                    case "OpenEspoCrmSettings":  fileName = "klear-settings.png"; break;
                    case "ComposeFromCase":      fileName = "klear-compose.png";  break;
                    default: return null;
                }
                return LoadEmbeddedBitmap(fileName, control.Id);
            }
            catch (Exception ex)
            {
                LogIconWarning(ex, "OnGetImage exception for {0}", control?.Id);
                return null;
            }
        }

        private static Bitmap? LoadEmbeddedBitmap(string fileName, string ribbonId)
        {
            var asm = Assembly.GetExecutingAssembly();
            var resourceName = "OutlookAddin.Images." + fileName;
            var stream = asm.GetManifestResourceStream(resourceName);
            if (stream == null)
            {
                // Help debug by listing every resource we DO have.
                var available = string.Join(", ", asm.GetManifestResourceNames());
                LogIconWarning(null,
                    "Icon resource not found: {0} (ribbon button {1}). Available resources: {2}",
                    resourceName, ribbonId, available);
                return null;
            }
            try
            {
                return new Bitmap(stream);
            }
            finally
            {
                stream.Dispose();
            }
        }

        private static void LogIconWarning(Exception? ex, string template, params object?[] args)
        {
            try
            {
                var logger = Globals.ThisAddIn?.AddInHost?.Logger;
                if (logger == null) return;
                if (ex != null) logger.Warning(ex, template, args);
                else logger.Warning(template, args);
            }
            catch { /* ignore — logging must never crash the ribbon */ }
        }
    }
}
