// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Security.Cryptography;
using System.Text;

namespace Microsoft.AspNetCore.Razor.Language
{
    internal class StringSourceDocument : RazorSourceDocument
    {
        private readonly string _content;
        private readonly RazorSourceLineCollection _lines;
        private byte[] _checksum;

        public StringSourceDocument(string content, Encoding encoding, RazorSourceDocumentProperties properties)
        {
            if (content == null)
            {
                throw new ArgumentNullException(nameof(content));
            }

            if (encoding == null)
            {
                throw new ArgumentNullException(nameof(encoding));
            }

            if (properties == null)
            {
                throw new ArgumentNullException(nameof(properties));
            }

            _content = content;
            Encoding = encoding;
            FilePath = properties.FilePath;
            RelativePath = properties.RelativePath;

            _lines = new DefaultRazorSourceLineCollection(this);
        }

        public override char this[int position] => _content[position];

        public override Encoding Encoding { get; }

        public override string FilePath { get; }

        public override int Length => _content.Length;

        public override RazorSourceLineCollection Lines => _lines;

        public override string RelativePath { get; }

        public override void CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count)
        {
            if (destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }

            if (sourceIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(sourceIndex));
            }

            if (destinationIndex < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(destinationIndex));
            }

            if (count < 0 || count > Length - sourceIndex || count > destination.Length - destinationIndex)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (count == 0)
            {
                return;
            }

            _content.CopyTo(sourceIndex, destination, destinationIndex, count);
        }

        public override byte[] GetChecksum()
        {
            if (_checksum == null)
            {
                var charBuffer = _content.ToCharArray();
                var encoder = Encoding.GetEncoder();
                var byteCount = encoder.GetByteCount(charBuffer, 0, charBuffer.Length, flush: true);
                var bytes = new byte[byteCount];
                encoder.GetBytes(charBuffer, 0, charBuffer.Length, bytes, 0, flush: true);

                using (var hashAlgorithm = SHA1.Create())
                {
                    _checksum = hashAlgorithm.ComputeHash(bytes);
                }
            }

            var copiedChecksum = new byte[_checksum.Length];
            _checksum.CopyTo(copiedChecksum, 0);

            return copiedChecksum;
        }
    }
}
