using CarneiroTech.Models;
using Microsoft.Extensions.Caching.Memory;
using System.Globalization;

namespace CarneiroTech.Services;

public class CaseService : ICaseService
{
    private readonly IMarkdownService _markdownService;
    private readonly IMemoryCache _cache;
    private readonly IWebHostEnvironment _environment;
    private readonly ILanguageService _languageService;
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly string _casesBasePath;
    private const string CACHE_KEY_PREFIX = "cases_";
    private const int CACHE_MINUTES = 60;

    public CaseService(IMarkdownService markdownService, IMemoryCache cache, IWebHostEnvironment environment,
                      ILanguageService languageService, IHttpContextAccessor httpContextAccessor)
    {
        _markdownService = markdownService;
        _cache = cache;
        _environment = environment;
        _languageService = languageService;
        _httpContextAccessor = httpContextAccessor;
        _casesBasePath = Path.Combine(_environment.ContentRootPath, "Content", "Cases");
    }

    private string GetCurrentLanguage()
    {
        if (_httpContextAccessor.HttpContext != null)
        {
            return _languageService.GetCurrentLanguage(_httpContextAccessor.HttpContext);
        }
        return "pt"; // Default fallback
    }

    private string GetCasesPath(string language)
    {
        return Path.Combine(_casesBasePath, language);
    }

    public async Task<List<CaseModel>> GetAllCasesAsync()
    {
        var language = GetCurrentLanguage();
        var cacheKey = $"{CACHE_KEY_PREFIX}{language}";

        if (_cache.TryGetValue(cacheKey, out List<CaseModel>? cachedCases) && cachedCases != null)
        {
            return cachedCases;
        }

        var cases = new List<CaseModel>();
        var casesPath = GetCasesPath(language);

        if (!Directory.Exists(casesPath))
        {
            // Try Portuguese as fallback
            casesPath = GetCasesPath("pt");
            if (!Directory.Exists(casesPath))
            {
                Directory.CreateDirectory(casesPath);
                return cases;
            }
        }

        var markdownFiles = Directory.GetFiles(casesPath, "*.md");

        foreach (var file in markdownFiles)
        {
            var caseModel = await ParseCaseFileAsync(file);
            if (caseModel != null)
            {
                cases.Add(caseModel);
            }
        }

        // Sort by order (ascending) and date (descending)
        cases = cases.OrderBy(c => c.Metadata.Order)
                     .ThenByDescending(c => c.Metadata.Date)
                     .ToList();

        _cache.Set(cacheKey, cases, TimeSpan.FromMinutes(CACHE_MINUTES));

        return cases;
    }

    public async Task<List<CaseModel>> GetFeaturedCasesAsync()
    {
        var allCases = await GetAllCasesAsync();
        return allCases.Where(c => c.Metadata.Featured).ToList();
    }

    public async Task<CaseModel?> GetCaseBySlugAsync(string slug)
    {
        var allCases = await GetAllCasesAsync();
        return allCases.FirstOrDefault(c => c.Metadata.Slug.Equals(slug, StringComparison.OrdinalIgnoreCase));
    }

    public async Task<List<string>> GetAllTagsAsync()
    {
        var allCases = await GetAllCasesAsync();
        var tags = allCases.SelectMany(c => c.Metadata.Tags)
                          .Distinct()
                          .OrderBy(t => t)
                          .ToList();
        return tags;
    }

    public async Task<List<CaseModel>> GetCasesByTagAsync(string tag)
    {
        var allCases = await GetAllCasesAsync();
        return allCases.Where(c => c.Metadata.Tags.Contains(tag, StringComparer.OrdinalIgnoreCase))
                      .ToList();
    }

    private async Task<CaseModel?> ParseCaseFileAsync(string filePath)
    {
        try
        {
            var content = await File.ReadAllTextAsync(filePath);
            var frontMatter = _markdownService.ParseFrontMatter(content, out string bodyContent);

            var metadata = new CaseMetadata
            {
                Title = GetStringValue(frontMatter, "title"),
                Slug = GetStringValue(frontMatter, "slug"),
                Summary = GetStringValue(frontMatter, "summary"),
                Client = GetStringValue(frontMatter, "client"),
                Industry = GetStringValue(frontMatter, "industry"),
                Timeline = GetStringValue(frontMatter, "timeline"),
                Role = GetStringValue(frontMatter, "role"),
                Image = GetStringValue(frontMatter, "image"),
                Tags = GetListValue(frontMatter, "tags"),
                Featured = GetBoolValue(frontMatter, "featured"),
                Order = GetIntValue(frontMatter, "order"),
                Date = GetDateValue(frontMatter, "date"),
                SeoTitle = GetStringValue(frontMatter, "seo_title"),
                SeoDescription = GetStringValue(frontMatter, "seo_description"),
                SeoKeywords = GetStringValue(frontMatter, "seo_keywords")
            };

            var htmlContent = _markdownService.ConvertToHtml(bodyContent);

            return new CaseModel
            {
                Metadata = metadata,
                ContentHtml = htmlContent,
                ContentMarkdown = bodyContent
            };
        }
        catch (Exception)
        {
            // Log error here if needed
            return null;
        }
    }

    private string GetStringValue(Dictionary<string, object> dict, string key)
    {
        return dict.ContainsKey(key) ? dict[key]?.ToString() ?? string.Empty : string.Empty;
    }

    private List<string> GetListValue(Dictionary<string, object> dict, string key)
    {
        if (!dict.ContainsKey(key)) return new List<string>();

        if (dict[key] is List<object> list)
        {
            return list.Select(item => item?.ToString() ?? string.Empty).ToList();
        }

        return new List<string>();
    }

    private bool GetBoolValue(Dictionary<string, object> dict, string key)
    {
        if (!dict.ContainsKey(key)) return false;

        var value = dict[key]?.ToString()?.ToLower();
        return value == "true" || value == "yes" || value == "1";
    }

    private int GetIntValue(Dictionary<string, object> dict, string key)
    {
        if (!dict.ContainsKey(key)) return 0;

        if (int.TryParse(dict[key]?.ToString(), out int result))
        {
            return result;
        }

        return 0;
    }

    private DateTime GetDateValue(Dictionary<string, object> dict, string key)
    {
        if (!dict.ContainsKey(key)) return DateTime.MinValue;

        var dateString = dict[key]?.ToString();
        if (DateTime.TryParse(dateString, CultureInfo.InvariantCulture, DateTimeStyles.None, out DateTime result))
        {
            return result;
        }

        return DateTime.MinValue;
    }
}
