using System;
using System.Drawing;
using System.IO;
using System.Linq;
using Semver;
using TsudaKageyu;
using Vestris.ResourceLib;

namespace KattekerCreator.Types
{
    public class AssemblyFileInfo
    {
        private readonly string _company;
        private readonly string _copyright;
        private readonly string _description;
        private readonly string _productName;

        public AssemblyFileInfo(string programFile, string version, string tempDir)
        {
            FileInfo = new FileInfo(programFile);
            using var resourceInfo = new ResourceInfo();
            resourceInfo.Load(programFile);
            if (resourceInfo.ResourceTypes.All(x => x.ResourceType != Kernel32.ResourceTypes.RT_VERSION)) return;
            var versionResource = (VersionResource)resourceInfo[Kernel32.ResourceTypes.RT_VERSION][0];
            var stringFileInfo = ((StringFileInfo)versionResource[nameof(StringFileInfo)]).Strings
                .FirstOrDefault().Value;
            AssemblyIconPath = GetAssemblyIcon(programFile, tempDir);
            if (stringFileInfo.Strings.ContainsKey("CompanyName"))
                _company = stringFileInfo.Strings["CompanyName"].StringValue.TrimEnd('\0');
            if (stringFileInfo.Strings.ContainsKey("FileDescription"))
                _description = stringFileInfo.Strings["FileDescription"].StringValue.TrimEnd('\0');
            if (stringFileInfo.Strings.ContainsKey("LegalCopyright"))
                _copyright = stringFileInfo.Strings["LegalCopyright"].StringValue.TrimEnd('\0');
            if (stringFileInfo.Strings.ContainsKey("ProductName"))
                _productName = stringFileInfo.Strings["ProductName"].StringValue.TrimEnd('\0');
            if (!stringFileInfo.Strings.ContainsKey("ProductVersion")) return;
            AssemblyVersion = version != null ? GetSemanticVersion(version) : GetSemanticVersion(stringFileInfo.Strings["ProductVersion"].StringValue.TrimEnd('\0'));
        }

        public string AssemblyIconPath { get; }

        public SemVersion AssemblyVersion { get; }

        public string Company => _company ?? string.Empty;

        public string Copyright => _copyright ?? string.Empty;

        public string Description => _description ?? string.Empty;

        public FileInfo FileInfo { get; }

        public string ProductName => _productName ?? Description;

        private static string GetAssemblyIcon(string programFile, string tempDir)
        {
            var applicationIcon = Path.Combine(tempDir, "application.ico");
            if (string.IsNullOrWhiteSpace(programFile)) throw new ApplicationException("Program not set.");
            if (!File.Exists(programFile)) throw new ApplicationException("Program not found.");
            if (File.Exists(applicationIcon)) File.Delete(applicationIcon);
            using (var fileStream = new FileStream(applicationIcon, FileMode.CreateNew))
            {
                try
                {
                    var ie = new IconExtractor(programFile);
                    using var icon = ie.GetIcon(0);
                    icon?.Save(fileStream);
                }
                catch (Exception)
                {
                    using var icon = Icon.ExtractAssociatedIcon(programFile);
                    icon?.Save(fileStream);
                }
            }

            return applicationIcon;
        }

        private static SemVersion GetSemanticVersion(string productVersion)
        {
            productVersion = productVersion.Replace(',', '.');
            if (SemVersion.TryParse(productVersion, out var semanticVersion))
                return semanticVersion?.Change(build: string.Empty);
            Version.TryParse(productVersion, out var version);
            return SemVersion.Parse(version.ToString(3));
        }
    }
}