using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Text.RegularExpressions;
using API.MangaDownloadClients;
using log4net;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;

namespace API.Schema.MangaConnectors;

[PrimaryKey("Name")]
public abstract class MangaConnector(string name, string[] supportedLanguages, string[] baseUris, string iconUrl)
{
    [JsonIgnore]
    [NotMapped]
    internal DownloadClient downloadClient { get; init; } = null!;

    [JsonIgnore]
    [NotMapped]
    protected ILog Log { get; init; } = LogManager.GetLogger(name);
    
    [StringLength(32)]
    [Required]
    public string Name { get; init; } = name;
    [StringLength(8)]
    [Required]
    public string[] SupportedLanguages { get; init; } = supportedLanguages;
    [StringLength(2048)]
    [Required]
    public string IconUrl { get; init; } = iconUrl;
    [StringLength(256)]
    [Required]
    public string[] BaseUris { get; init; } = baseUris;
    [Required]
    public bool Enabled { get; internal set; } = true;
    
    public abstract Manga[] SearchManga(string mangaSearchName);

    public abstract Manga? GetMangaFromUrl(string url);

    public abstract Manga? GetMangaFromId(string mangaIdOnSite);
    
    public abstract Chapter[] GetChapters(Manga manga, string? language = null);

    internal abstract string[] GetChapterImageUrls(Chapter chapter);

    public bool UrlMatchesConnector(string url) => BaseUris.Any(baseUri => Regex.IsMatch(url, "https?://" + baseUri + "/.*"));
    
    internal string? SaveCoverImageToCache(Manga manga, int retries = 3)
    {
        if(retries < 0)
            return null;
        
        Regex urlRex = new (@"https?:\/\/((?:[a-zA-Z0-9-]+\.)+[a-zA-Z0-9]+)\/(?:.+\/)*(.+\.([a-zA-Z]+))");
        //https?:\/\/[a-zA-Z0-9-]+\.([a-zA-Z0-9-]+\.[a-zA-Z0-9]+)\/(?:.+\/)*(.+\.([a-zA-Z]+)) for only second level domains
        Match match = urlRex.Match(manga.CoverUrl);
        string filename = $"{match.Groups[1].Value}-{manga.MangaId}.{match.Groups[3].Value}";
        string saveImagePath = Path.Join(TrangaSettings.coverImageCache, filename);

        if (File.Exists(saveImagePath))
            return saveImagePath;
        
        RequestResult coverResult = downloadClient.MakeRequest(manga.CoverUrl, RequestType.MangaCover, $"https://{match.Groups[1].Value}");
        if ((int)coverResult.statusCode < 200 || (int)coverResult.statusCode >= 300)
            return SaveCoverImageToCache(manga, --retries);
            
        using MemoryStream ms = new();
        coverResult.result.CopyTo(ms);
        Directory.CreateDirectory(TrangaSettings.coverImageCache);
        File.WriteAllBytes(saveImagePath, ms.ToArray());
        
        return saveImagePath;
    }
}