using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using CsvHelper;
using CsvHelper.Configuration;
using SharepointToolbox.Core.Models;

namespace SharepointToolbox.Services;

public class CsvValidationService : ICsvValidationService
{
    private static readonly Regex EmailRegex = new(
        @"^[^@\s]+@[^@\s]+\.[^@\s]+$", RegexOptions.Compiled);

    public List<CsvValidationRow<T>> ParseAndValidate<T>(Stream csvStream) where T : class
    {
        using var reader = new StreamReader(csvStream, Encoding.UTF8, detectEncodingFromByteOrderMarks: true);
        using var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture)
        {
            HasHeaderRecord = true,
            MissingFieldFound = null,
            HeaderValidated = null,
            DetectDelimiter = true,
            TrimOptions = TrimOptions.Trim,
        });

        var rows = new List<CsvValidationRow<T>>();
        csv.Read();
        csv.ReadHeader();
        while (csv.Read())
        {
            try
            {
                var record = csv.GetRecord<T>();
                if (record == null)
                {
                    rows.Add(CsvValidationRow<T>.ParseError(csv.Context.Parser?.RawRecord ?? string.Empty, "Failed to parse row"));
                    continue;
                }
                rows.Add(new CsvValidationRow<T>(record, new List<string>()));
            }
            catch (Exception ex)
            {
                rows.Add(CsvValidationRow<T>.ParseError(csv.Context.Parser?.RawRecord ?? string.Empty, ex.Message));
            }
        }
        return rows;
    }

    public List<CsvValidationRow<BulkMemberRow>> ParseAndValidateMembers(Stream csvStream)
    {
        var rows = ParseAndValidate<BulkMemberRow>(csvStream);
        foreach (var row in rows.Where(r => r.IsValid && r.Record != null))
        {
            var errors = ValidateMemberRow(row.Record!);
            row.Errors.AddRange(errors);
        }
        return rows;
    }

    public List<CsvValidationRow<BulkSiteRow>> ParseAndValidateSites(Stream csvStream)
    {
        var rows = ParseAndValidate<BulkSiteRow>(csvStream);
        foreach (var row in rows.Where(r => r.IsValid && r.Record != null))
        {
            var errors = ValidateSiteRow(row.Record!);
            row.Errors.AddRange(errors);
        }
        return rows;
    }

    public List<CsvValidationRow<FolderStructureRow>> ParseAndValidateFolders(Stream csvStream)
    {
        var rows = ParseAndValidate<FolderStructureRow>(csvStream);
        foreach (var row in rows.Where(r => r.IsValid && r.Record != null))
        {
            var errors = ValidateFolderRow(row.Record!);
            row.Errors.AddRange(errors);
        }
        return rows;
    }

    private static List<string> ValidateMemberRow(BulkMemberRow row)
    {
        var errors = new List<string>();
        if (string.IsNullOrWhiteSpace(row.Email))
            errors.Add("Email is required");
        else if (!EmailRegex.IsMatch(row.Email.Trim()))
            errors.Add($"Invalid email format: {row.Email}");

        if (string.IsNullOrWhiteSpace(row.GroupName) && string.IsNullOrWhiteSpace(row.GroupUrl))
            errors.Add("GroupName or GroupUrl is required");

        if (!string.IsNullOrWhiteSpace(row.Role) &&
            !row.Role.Equals("Member", StringComparison.OrdinalIgnoreCase) &&
            !row.Role.Equals("Owner", StringComparison.OrdinalIgnoreCase))
            errors.Add($"Role must be 'Member' or 'Owner', got: {row.Role}");

        return errors;
    }

    private static List<string> ValidateSiteRow(BulkSiteRow row)
    {
        var errors = new List<string>();
        if (string.IsNullOrWhiteSpace(row.Name))
            errors.Add("Name is required");

        if (string.IsNullOrWhiteSpace(row.Type))
            errors.Add("Type is required");
        else if (!row.Type.Equals("Team", StringComparison.OrdinalIgnoreCase) &&
                 !row.Type.Equals("Communication", StringComparison.OrdinalIgnoreCase))
            errors.Add($"Type must be 'Team' or 'Communication', got: {row.Type}");

        // Team sites require at least one owner (Pitfall 6 from research)
        if (row.Type.Equals("Team", StringComparison.OrdinalIgnoreCase) &&
            string.IsNullOrWhiteSpace(row.Owners))
            errors.Add("Team sites require at least one owner");

        // Team sites need an alias
        if (row.Type.Equals("Team", StringComparison.OrdinalIgnoreCase) &&
            string.IsNullOrWhiteSpace(row.Alias))
            errors.Add("Team sites require an alias");

        return errors;
    }

    private static List<string> ValidateFolderRow(FolderStructureRow row)
    {
        var errors = new List<string>();
        if (string.IsNullOrWhiteSpace(row.Level1))
            errors.Add("Level1 is required (root folder)");
        return errors;
    }
}
