using AuthorBuddy.Web.Data;
using AuthorBuddy.Web.Models;
using LiteDB;

namespace AuthorBuddy.Web.Services;

public class ProjectService : IProjectService
{
    private readonly ILiteDatabase _db;
    private readonly IFileScannerService _fileScannerService;

    public ProjectService(ILiteDatabase db, IFileScannerService fileScannerService)
    {
        _db = db;
        _fileScannerService = fileScannerService;
    }

    public Task<int> CreateNewProjectAsync(string projectName, string rootPath)
    {
        string[] subFolders = { "00_Drafts", "01_Fakten", "02_Characters", "03_Archive" };
        foreach (var subFolder in subFolders)
        {
            Directory.CreateDirectory(Path.Combine(rootPath, subFolder));
        }

        string readmePath = Path.Combine(rootPath, "00_Projekt_Info.md");
        File.WriteAllText(readmePath, $"# Projekt: {projectName}\nErstellt am: {DateTime.Now}");

        var col = _db.GetCollection<ProjectEntity>("projects");
        var entity = new ProjectEntity
        {
            Name = projectName,
            RootPath = rootPath,
            LastOpened = DateTime.Now
        };

        col.Insert(entity);
        return Task.FromResult(entity.Id);
    }

    public Task<List<Project>> GetAllProjectsAsync()
    {
        var col = _db.GetCollection<ProjectEntity>("projects");
        var list = col.FindAll()
            .OrderByDescending(p => p.LastOpened)
            .Select(p => new Project
            {
                Id = p.Id,
                Name = p.Name,
                RootPath = p.RootPath
            })
            .ToList();
        return Task.FromResult(list);
    }

    public Task<Project?> GetProjectAsync(int projectId)
    {
        var col = _db.GetCollection<ProjectEntity>("projects");
        var entity = col.FindById(projectId);
        if (entity == null) return Task.FromResult<Project?>(null);
        return Task.FromResult<Project?>(new Project
        {
            Id = entity.Id,
            Name = entity.Name,
            RootPath = entity.RootPath
        });
    }

    public Task<List<FileTreeItem>> GetProjectFileTreeAsync(int projectId)
    {
        var col = _db.GetCollection<ProjectEntity>("projects");
        var entity = col.FindById(projectId);
        if (entity == null || !Directory.Exists(entity.RootPath))
            return Task.FromResult(new List<FileTreeItem>());

        var result = new List<FileTreeItem>();
        BuildTree(entity.RootPath, result, 0);
        return Task.FromResult(result);
    }

    private static void BuildTree(string directory, List<FileTreeItem> items, int depth)
    {
        if (depth > 4) return;

        var dirInfo = new DirectoryInfo(directory);
        if (!dirInfo.Exists) return;

        foreach (var dir in dirInfo.GetDirectories().OrderBy(d => d.Name))
        {
            var node = new FileTreeItem
            {
                Name = dir.Name,
                FullPath = dir.FullName,
                IsDirectory = true
            };
            BuildTree(dir.FullName, node.Children, depth + 1);
            if (node.Children.Count > 0 || dir.Name.StartsWith("00_") || dir.Name.StartsWith("01_") || dir.Name.StartsWith("02_"))
                items.Add(node);
        }

        foreach (var file in dirInfo.GetFiles("*.md").OrderBy(f => f.Name))
        {
            items.Add(new FileTreeItem
            {
                Name = file.Name,
                FullPath = file.FullName,
                IsDirectory = false
            });
        }
    }

    public async Task SyncProjectFilesAsync(int projectId, string directoryPath, IProgress<string> progress)
    {
        await _fileScannerService.ScanProjectFolderAsync(projectId, directoryPath, progress);
    }

    public Task<int> CopyProjectAsync(int sourceProjectId, string newName, string newRootPath, int userId)
    {
        var col = _db.GetCollection<ProjectEntity>("projects");
        var source = col.FindById(sourceProjectId);
        if (source == null)
            throw new InvalidOperationException("Source project not found.");

        Directory.CreateDirectory(newRootPath);
        CopyDirectory(source.RootPath, newRootPath);

        var entity = new ProjectEntity
        {
            Name = newName,
            RootPath = newRootPath,
            LastOpened = DateTime.Now
        };
        col.Insert(entity);

        var settings = _db.GetCollection<SettingEntity>("settings");
        var projectSettings = settings.Find(s =>
            s.UserId == userId && s.ProjectId == sourceProjectId);
        foreach (var s in projectSettings)
        {
            settings.Insert(new SettingEntity
            {
                Key = s.Key,
                Value = s.Value,
                UserId = userId,
                ProjectId = entity.Id
            });
        }

        return Task.FromResult(entity.Id);
    }

    private static void CopyDirectory(string sourceDir, string destDir)
    {
        foreach (var dir in Directory.GetDirectories(sourceDir, "*", SearchOption.AllDirectories))
        {
            Directory.CreateDirectory(dir.Replace(sourceDir, destDir));
        }
        foreach (var file in Directory.GetFiles(sourceDir, "*.*", SearchOption.AllDirectories))
        {
            var dest = file.Replace(sourceDir, destDir);
            File.Copy(file, dest, true);
        }
    }
}
