using System.Diagnostics;
using FrymasterBadgeApp.Services;
using Microsoft.Data.SqlClient;
using Microsoft.Maui.Storage;

namespace FrymasterBadgeApp;

public partial class CompanyPage : ContentPage
{
    private readonly SqlService _db;
    private Dictionary<string, object>? _selectedCompany;
    private string _tempLogoPath = "";
    private const string LogoPathKey = "LogoBasePath";

/// <summary>
/// Constructor for CompanyPage.
/// of type ContentPage.
/// the main page for viewing and editing company information.
/// <param name="db">The SQLService object used to access the database.</param>
    public CompanyPage(SqlService db)
    {
        InitializeComponent();
        _db = db;

        Shell.SetBackButtonBehavior(
            this,
            new BackButtonBehavior
            {
                TextOverride = "Back",
                Command = new Command(async () => await Shell.Current.GoToAsync("..")),
            } 
        );

        LoadCompanies();
    }

        /// <summary>
        /// Returns the path to the directory used to store company logos.
        /// </summary>
        /// <returns>The path to the directory used to store company logos.</returns>
    private string GetLogoDirectory() =>
        Preferences.Default.Get(LogoPathKey, @"C:\FrymasterData\logos");

/// <summary>
/// Loads the list of companies from the database.
/// the results are ordered by company name (ascending).
/// and displays the companies are stored in the CompanyList.
/// </summary>
    private void LoadCompanies()
    {
        try
        {
            var companies = _db.Query("SELECT * FROM Companies ORDER BY Name ASC", null);
            CompanyList.ItemsSource = companies;
        }
        catch (Exception ex)
        {
            AppLogger.Error("Failed to load companies", ex);
            DisplayAlert("Error", "Failed to load companies.", "OK");
        }
    }

/// <summary>
/// Called when the selection in the companies list changes.
/// the selection is used to update the company name, address, city, state, zip code, and delete button visibility.
/// </summary>
    private void OnCompanySelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        var selected = e.CurrentSelection.FirstOrDefault() as Dictionary<string, object>;
        if (selected == null)
        {
            ClearFields();
            return;
        }

        _selectedCompany = selected;

        MainThread.BeginInvokeOnMainThread(async () =>
        {
            CompName.Text = GetValue(selected, "Name");
            CompAddress.Text = GetValue(selected, "Address");
            CompCity.Text = GetValue(selected, "City");
            CompState.Text = GetValue(selected, "State");
            CompZip.Text = GetValue(selected, "Zip");
            DeleteBtn.IsVisible = true;

            LogoPreview.Source = null;
            _tempLogoPath = "";

            // Get stored filename only
            string storedFileName = GetValue(selected, "logo");
            if (!string.IsNullOrWhiteSpace(storedFileName))
            {
                string logoDir = GetLogoDirectory();
                string fullPath = Path.Combine(logoDir, storedFileName);

                if (File.Exists(fullPath))
                {
                    _tempLogoPath = fullPath;
                    LogoPreview.Source = ImageSource.FromFile(fullPath);
                    AppLogger.Info($"Logo loaded for company: {fullPath}");
                }
                else
                {
                    AppLogger.Warning($"Logo file missing: {fullPath}");
                }
            }
        });
    }

/// <summary>
/// Returns the value of the given key from the dictionary, trimmed of whitespace.
/// If the key does not exist, an empty string is returned.
/// </summary>
/// <param name="dict">The dictionary to search.</param>
/// <param name="key">The key to search for.</param>
/// <returns>The value of the given key, trimmed of whitespace, or an empty string if the key does not exist.</returns>
    private string GetValue(Dictionary<string, object> dict, string key)
    {
        var actualKey = dict.Keys.FirstOrDefault(k =>
            k.Equals(key, StringComparison.OrdinalIgnoreCase)
        );
        return actualKey != null ? dict[actualKey]?.ToString()?.Trim() ?? "" : "";
    }

/// <summary>
/// Called when the user selects a logo image from the file picker.
/// </summary>
/// <param name="sender">The object that triggered the event</param>
/// <param name="e">The event data which contains information about the event</param>
    private async void OnSelectLogoClicked(object sender, EventArgs e)
    {
        try
        {
            var result = await FilePicker.Default.PickAsync(
                new PickOptions
                {
                    PickerTitle = "Select Company Logo",
                    FileTypes = FilePickerFileType.Images,
                }
            );

            if (result != null)
            {
                _tempLogoPath = result.FullPath;
                LogoPreview.Source = ImageSource.FromFile(_tempLogoPath);
            }
        }
        catch (Exception ex)
        {
            await DisplayAlert("Error", $"Failed to select logo: {ex.Message}", "OK");
        }
    }

/// <summary>
/// Save the selected company to the database.
/// </summary>
/// <param name="sender">The object that invoked this method.</param>
/// <param name="e">The event data for this method.</param>
    private async void OnSaveClicked(object sender, EventArgs e)
    {
        if (string.IsNullOrWhiteSpace(CompName.Text))
        {
            await DisplayAlert("Error", "Company Name is required", "OK");
            return;
        }

        string logoDir = GetLogoDirectory();
        if (!Directory.Exists(logoDir))
        {
            try
            {
                Directory.CreateDirectory(logoDir);
            }
            catch
            {
                await DisplayAlert("Error", "Cannot create logo directory.", "OK");
                return;
            }
        }

        string logoFileNameToSave = ""; // will be stored in DB

        if (!string.IsNullOrEmpty(_tempLogoPath))
        {
            try
            {
                string originalFileName = Path.GetFileName(_tempLogoPath);
                string extension = Path.GetExtension(originalFileName);
                string baseName = Path.GetFileNameWithoutExtension(originalFileName);

                // Avoid overwrites: add timestamp if file already exists
                string destFileName = originalFileName;
                string destPath = Path.Combine(logoDir, destFileName);

                if (File.Exists(destPath))
                {
                    destFileName = $"{baseName}_{DateTime.Now:yyyyMMdd_HHmmss}{extension}";
                    destPath = Path.Combine(logoDir, destFileName);
                }

                File.Copy(_tempLogoPath, destPath, true);
                logoFileNameToSave = destFileName; // only filename saved to DB
                _tempLogoPath = destPath; // update local temp for preview

                AppLogger.Info($"Logo saved as: {destPath}");
            }
            catch (Exception ex)
            {
                AppLogger.Error("Failed to copy logo", ex);
                await DisplayAlert("Error", "Failed to save logo file.", "OK");
                return;
            }
        }

        try
        {
            var parameters = new List<SqlParameter>
            {
                new("@n", CompName.Text ?? ""),
                new("@a", CompAddress.Text ?? ""),
                new("@c", CompCity.Text ?? ""),
                new("@s", CompState.Text ?? ""),
                new("@z", CompZip.Text ?? ""),
                new("@l", logoFileNameToSave), // ← only filename
            };

            if (_selectedCompany == null)
            {
                _db.Execute(
                    "INSERT INTO Companies (Name, Address, City, State, Zip, logo) VALUES (@n, @a, @c, @s, @z, @l)",
                    parameters.ToArray()
                );
                await DisplayAlert("Success", "Company added.", "OK");
            }
            else
            {
                parameters.Add(new("@id", _selectedCompany["ID"]));
                _db.Execute(
                    "UPDATE Companies SET Name=@n, Address=@a, City=@c, State=@s, Zip=@z, logo=@l WHERE ID=@id",
                    parameters.ToArray()
                );
                await DisplayAlert("Success", "Company updated.", "OK");
            }

            LoadCompanies();
            ClearFields();
        }
        catch (Exception ex)
        {
            AppLogger.Error("Database save failed", ex);
            await DisplayAlert("Database Error", ex.Message, "OK");
        }
    }

/// <summary>
/// Resets the UI state after clicking the "Add New" button.
/// </summary>
    private void OnAddNewClicked(object sender, EventArgs e)
    {
        CompanyList.SelectedItem = null;
        ClearFields();
    }

/// <summary>
/// Resets the UI state after clicking the "Add New" button or deleting a company.
/// </summary>
    private void ClearFields()
    {
        _selectedCompany = null;
        _tempLogoPath = "";
        CompName.Text = CompAddress.Text = CompCity.Text = CompState.Text = CompZip.Text = "";
        LogoPreview.Source = null;
        DeleteBtn.IsVisible = false;
    }

/// <summary>
/// Delete a company from the database.
/// </summary>
    private async void OnDeleteClicked(object sender, EventArgs e)
    {
        if (_selectedCompany == null)
            return;

        if (await DisplayAlert("Confirm", $"Delete {CompName.Text}?", "Yes", "No"))
        {
            try
            {
                _db.Execute(
                    "DELETE FROM Companies WHERE ID=@id",
                    new SqlParameter[] { new("@id", _selectedCompany["ID"]) }
                );
                LoadCompanies();
                ClearFields();
            }
            catch (Exception ex)
            {
                await DisplayAlert("Error", ex.Message, "OK");
            }
        }
    }
}
