using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

namespace TradeApp.WinForms.V08;

public sealed partial class ProductEditForm : Form
{
    private readonly DatabaseClient _db;
    private readonly ProductView _product;
    private readonly string _originalImagePath;

    public ProductEditForm(DatabaseClient db, ProductView? product)
    {
        _db = db;
        _product = product ?? new ProductView();
        _originalImagePath = _product.ImagePath;
        InitializeComponent();
        Text = product is null ? "Добавление товара" : "Редактирование товара";
        LoadLookups();
        Fill();
    }

    private void ChooseImageButton_Click(object? sender, EventArgs e)
    {
        using var dialog = new OpenFileDialog { Filter = "Изображения|*.jpg;*.jpeg;*.png;*.bmp" };
        if (dialog.ShowDialog(this) != DialogResult.OK)
        {
            return;
        }

        var targetDir = Path.Combine(AppContext.BaseDirectory, "Images");
        Directory.CreateDirectory(targetDir);
        var targetName = Path.GetFileName(dialog.FileName);
        var targetPath = Path.Combine(targetDir, targetName);
        if (!string.Equals(Path.GetFullPath(dialog.FileName), Path.GetFullPath(targetPath), StringComparison.OrdinalIgnoreCase))
        {
            SaveProductImage(dialog.FileName, targetPath);
        }

        imageTextBox.Text = targetName;
    }

    private void SaveButton_Click(object? sender, EventArgs e)
    {
        if (string.IsNullOrWhiteSpace(articleTextBox.Text) || string.IsNullOrWhiteSpace(nameTextBox.Text))
        {
            MessageBox.Show("Артикул и название обязательны.", "Ошибка", MessageBoxButtons.OK, MessageBoxIcon.Error);
            return;
        }

        _product.Article = articleTextBox.Text.Trim();
        _product.Name = nameTextBox.Text.Trim();
        _product.Unit = unitComboBox.Text.Trim();
        _product.Price = priceNumeric.Value;
        _product.Supplier = supplierComboBox.Text.Trim();
        _product.Manufacturer = manufacturerComboBox.Text.Trim();
        _product.Category = categoryComboBox.Text.Trim();
        _product.DiscountPercent = discountNumeric.Value;
        _product.StockQuantity = (int)stockNumeric.Value;
        _product.Description = descriptionTextBox.Text.Trim();
        _product.ImagePath = string.IsNullOrWhiteSpace(imageTextBox.Text) ? "picture.png" : imageTextBox.Text.Trim();
        _db.SaveProduct(_product);
        DeleteReplacedImage(_originalImagePath, _product.ImagePath);
        DialogResult = DialogResult.OK;
    }

    private void LoadLookups()
    {
        unitComboBox.Items.AddRange(_db.LoadUnits().Cast<object>().ToArray());
        supplierComboBox.Items.AddRange(_db.LoadSuppliers().Cast<object>().ToArray());
        manufacturerComboBox.Items.AddRange(_db.LoadManufacturers().Cast<object>().ToArray());
        categoryComboBox.Items.AddRange(_db.LoadCategories().Cast<object>().ToArray());
    }

    private void Fill()
    {
        articleTextBox.Text = _product.Article;
        nameTextBox.Text = _product.Name;
        unitComboBox.Text = _product.Unit;
        priceNumeric.Value = Clamp(_product.Price, priceNumeric.Minimum, priceNumeric.Maximum);
        supplierComboBox.Text = _product.Supplier;
        manufacturerComboBox.Text = _product.Manufacturer;
        categoryComboBox.Text = _product.Category;
        discountNumeric.Value = Clamp(_product.DiscountPercent, discountNumeric.Minimum, discountNumeric.Maximum);
        stockNumeric.Value = Clamp(_product.StockQuantity, stockNumeric.Minimum, stockNumeric.Maximum);
        descriptionTextBox.Text = _product.Description;
        imageTextBox.Text = string.IsNullOrWhiteSpace(_product.ImagePath) ? "picture.png" : _product.ImagePath;
    }

    private static decimal Clamp(decimal value, decimal minimum, decimal maximum)
    {
        return Math.Min(Math.Max(value, minimum), maximum);
    }

    private static void SaveProductImage(string sourcePath, string targetPath)
    {
        using var source = Image.FromFile(sourcePath);
        var scale = Math.Min(1d, Math.Min(300d / source.Width, 200d / source.Height));
        var width = Math.Max(1, (int)Math.Round(source.Width * scale));
        var height = Math.Max(1, (int)Math.Round(source.Height * scale));

        using var resized = new Bitmap(width, height);
        resized.SetResolution(source.HorizontalResolution, source.VerticalResolution);
        using (var graphics = Graphics.FromImage(resized))
        {
            graphics.Clear(Color.Transparent);
            graphics.CompositingQuality = CompositingQuality.HighQuality;
            graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
            graphics.SmoothingMode = SmoothingMode.HighQuality;
            graphics.DrawImage(source, 0, 0, width, height);
        }

        if (File.Exists(targetPath))
        {
            File.Delete(targetPath);
        }

        resized.Save(targetPath, source.RawFormat);
    }

    private void DeleteReplacedImage(string oldImagePath, string newImagePath)
    {
        if (string.IsNullOrWhiteSpace(oldImagePath) ||
            oldImagePath.Equals(newImagePath, StringComparison.OrdinalIgnoreCase) ||
            oldImagePath.Equals("picture.png", StringComparison.OrdinalIgnoreCase) ||
            _db.ProductImageIsUsed(oldImagePath, _product.ProductId))
        {
            return;
        }

        var path = Path.Combine(AppContext.BaseDirectory, "Images", oldImagePath);
        if (!File.Exists(path))
        {
            return;
        }

        try
        {
            File.Delete(path);
        }
        catch (IOException)
        {
            MessageBox.Show("Старое фото сохранено, потому что файл сейчас занят.", "Фото товара", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
        catch (UnauthorizedAccessException)
        {
            MessageBox.Show("Старое фото не удалено: нет доступа к файлу.", "Фото товара", MessageBoxButtons.OK, MessageBoxIcon.Warning);
        }
    }
}