// Copyright (c) 2023 Timothy Schenk. Subject to the GNU AGPL Version 3 License.

using System.Security.Cryptography;
using System.Text;
using MassTransit.Mediator;
using Microsoft.Extensions.Logging;
using NetCoreServer;

namespace Continuity.AuthServer;

public class ChannelSession : TcpSession
{
    private static readonly byte[] _key = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7 }
        .Reverse().ToArray();

    private static readonly byte[] _iv = new byte[]
    {
        0xfe, 220, 0xba, 0x98, 0x76, 0x54, 50, 0x10, 15, 30, 0x2d, 60, 0x4b, 90, 0x69, 120
    }.Reverse().ToArray();

    private readonly ICryptoTransform _decryptor;

    private readonly ICryptoTransform _encryptor;
    private readonly ILogger<ChannelSession> _logger;
    private readonly IMediator _mediator;

    public ChannelSession(TcpServer server, IMediator mediator, ILogger<ChannelSession> logger) : base(server)
    {
        _mediator = mediator;
        _logger = logger;
        var aes = Aes.Create();
        aes.Key = _key;
        aes.IV = _iv;
        aes.Padding = PaddingMode.None;
#pragma warning disable SEC0026
        aes.Mode = CipherMode.ECB;
#pragma warning restore SEC0026

        _decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
        _encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
    }

    protected override void OnReceived(byte[] buffer, long offset, long size)
    {
        try
        {
            using (var ms = new MemoryStream(Decrypt(buffer)))
            using (var cs = new CryptoStream(ms, _decryptor, CryptoStreamMode.Read))
            {
                var amountOfReadBytes = cs.Read(buffer);
                if (amountOfReadBytes != buffer.Length)
                {
                    _logger.LogError("Amount of read bytes is not equal to buffer length.");
                }
            }

            base.OnReceived(buffer, offset, size);
        }
        catch (CryptographicException ex)
        {
            _logger.LogError("An error has occured while decrypting: {ErrorMessage}", ex.Message);
            _logger.LogError("Default buffer message: {Message}", Encoding.ASCII.GetString(buffer));
        }
    }

    private static byte[] Decrypt(byte[] buffer)
    {
        for (var i = 0; i < buffer.Length; ++i)
        {
            buffer[i] = (byte)(buffer[i] ^ i ^ (3 * (0xFE - i)));
        }

        return buffer;
    }
}