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

using System.Diagnostics;
using System.IO;

namespace Microsoft.AspNetCore.Razor.Language
{
    /// <summary>
    /// An item in a <see cref="RazorProjectFileSystem"/>.
    /// </summary>
    [DebuggerDisplay("{" + nameof(DebuggerToString) + "()}")]
    public abstract class RazorProjectItem
    {
        /// <summary>
        /// Path specified in <see cref="RazorProject.EnumerateItems(string)"/>.
        /// </summary>
        public abstract string BasePath { get; }

        /// <summary>
        /// File path relative to <see cref="BasePath"/>. This property uses the project path syntax,
        /// using <c>/</c> as a path separator and does not follow the operating system's file system
        /// conventions.
        /// </summary>
        public abstract string FilePath { get; }

        /// <summary>
        /// The absolute physical (file system) path to the file, including the file name.
        /// </summary>
        public abstract string PhysicalPath { get; }

        /// <summary>
        /// The relative physical (file system) path to the file, including the file name. Relative to the
        /// physical path of the <see cref="BasePath"/>.
        /// </summary>
        public virtual string RelativePhysicalPath => null;

        /// <summary>
        /// A scope identifier that will be used on elements in the generated class, or null.
        /// </summary>
        public virtual string CssScope { get; }

        /// <summary>
        /// Gets the document kind that should be used for the generated document. If possible this will be inferred from the file path. May be null.
        /// </summary>
        public virtual string FileKind
        {
            get
            {
                return FilePath == null ? null : FileKinds.GetFileKindFromFilePath(FilePath);
            }
        }

        /// <summary>
        /// Gets the file contents as readonly <see cref="Stream"/>.
        /// </summary>
        /// <returns>The <see cref="Stream"/>.</returns>
        public abstract Stream Read();

        /// <summary>
        /// Gets a value that determines if the file exists.
        /// </summary>
        public abstract bool Exists { get; }

        /// <summary>
        /// The root relative path of the item.
        /// </summary>
        public string CombinedPath
        {
            get
            {
                if (BasePath == "/")
                {
                    return FilePath;
                }
                else
                {
                    return BasePath + FilePath;
                }
            }
        }

        /// <summary>
        /// The extension of the file.
        /// </summary>
        public string Extension
        {
            get
            {
                var index = FileName.LastIndexOf('.');
                if (index == -1)
                {
                    return null;
                }
                else
                {
                    return FileName.Substring(index);
                }
            }
        }

        /// <summary>
        /// The name of the file including the extension.
        /// </summary>
        public string FileName
        {
            get
            {
                var index = FilePath.LastIndexOf('/');
                return FilePath.Substring(index + 1);
            }
        }

        /// <summary>
        /// File path relative to <see cref="BasePath"/> without the extension.
        /// </summary>
        public string FilePathWithoutExtension
        {
            get
            {
                var index = FilePath.LastIndexOf('.');
                if (index == -1)
                {
                    return FilePath;
                }
                else
                {
                    return FilePath.Substring(0, index);
                }
            }
        }

        internal RazorSourceDocument RazorSourceDocument { get; set; }

        private string DebuggerToString()
        {
            return CombinedPath;
        }
    }
}
