using System;
using System.Threading;
using System.Threading.Tasks;
using FoodsharingSiegen.Contracts.Model;
using FoodsharingSiegen.Server.Service;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Options;
using MimeKit;
using Moq;
using Xunit;

namespace FoodsharingSiegen.Tests
{
    public class MailServiceTests
    {
        private readonly Mock<IOptions<AppSettings>> _mockOptions;
        private readonly AppSettings _appSettings;
        private readonly Mock<ISmtpClient> _mockSmtpClient;

        public MailServiceTests()
        {
            _appSettings = new AppSettings
            {
                Mail = new MailSettings
                {
                    Host = "smtp.test.com",
                    Port = 587,
                    UseSsl = false,
                    Username = "user@test.com",
                    Password = "password123",
                    FromAddress = "no-reply@test.com"
                },
                Terms = new TermSettings
                {
                    Title = "Foodsharing Test"
                }
            };

            _mockOptions = new Mock<IOptions<AppSettings>>();
            _mockOptions.Setup(o => o.Value).Returns(_appSettings);

            _mockSmtpClient = new Mock<ISmtpClient>();
        }

        [Fact]
        public async Task SendEmailAsync_ConnectsAuthenticatesAndSendsEmail()
        {
            // Arrange
            var service = new MailService(_mockOptions.Object, () => _mockSmtpClient.Object);
            var toEmail = "recipient@test.com";
            var subject = "Test Subject";
            var body = "<p>Test Body</p>";

            // Act
            await service.SendEmailAsync(toEmail, subject, body);

            // Assert
            _mockSmtpClient.Verify(
                x => x.ConnectAsync(
                    "smtp.test.com", 
                    587, 
                    SecureSocketOptions.Auto, 
                    It.IsAny<CancellationToken>()), 
                Times.Once);

            _mockSmtpClient.Verify(
                x => x.AuthenticateAsync(
                    "user@test.com", 
                    "password123", 
                    It.IsAny<CancellationToken>()), 
                Times.Once);

            // Verify a MimeMessage is passed to SendAsync with correct attributes
            _mockSmtpClient.Verify(
                x => x.SendAsync(
                    It.Is<MimeMessage>(m => m.Subject == subject),
                    It.IsAny<CancellationToken>(), 
                    It.IsAny<MailKit.ITransferProgress>()), 
                Times.Once);

            _mockSmtpClient.Verify(
                x => x.DisconnectAsync(
                    true, 
                    It.IsAny<CancellationToken>()), 
                Times.Once);
            
            _mockSmtpClient.Verify(
                x => x.Dispose(), 
                Times.Once);
        }

        [Fact]
        public async Task SendEmailAsync_SkipsAuthentication_WhenUsernameIsBlank()
        {
            // Arrange
            _appSettings.Mail.Username = "";
            _appSettings.Mail.Password = "";
            var service = new MailService(_mockOptions.Object, () => _mockSmtpClient.Object);

            // Act
            await service.SendEmailAsync("recipient@test.com", "Subject", "Body");

            // Assert
            _mockSmtpClient.Verify(
                x => x.AuthenticateAsync(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<CancellationToken>()), 
                Times.Never);
        }
    }
}