
using System;
using YoutubeExplode.Playlists;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using YoutubeExplode;
using System.Text;
using System.Net.Http.Headers;
using System.Net.Http;
using System.IO;
using YoutubeExplode.Channels;
using System.Net;
using System.Text.RegularExpressions;
using System.Drawing;
using YoutubeExplode.Videos.Streams;
using YoutubeExplode.Videos;
using AngleSharp.Common;
using System.Runtime.InteropServices;

namespace DL.Controllers
{
    [Route("Grabber")]
    [ApiController]

    public class YoutubeController : ControllerBase
    {
        private static bool ChannelIsValid(string id)
        {
            if (string.IsNullOrWhiteSpace(id))
                return false;

            // Channel IDs should start with these characters
            if (!id.StartsWith("UC", StringComparison.Ordinal))
                return false;

            // Channel IDs are always 24 characters
            if (id.Length != 24)
                return false;

            return !Regex.IsMatch(id, @"[^0-9a-zA-Z_\-]");
        }
        public string fixstr(string inputString)
        {

            string pattern = " *[\\~#%&*{}/:<>?|\"-]+ *";
            string replacement = "_";

            Regex regEx = new Regex(pattern);
            string sanitized = regEx.Replace(inputString, replacement);
            string asAscii = Encoding.ASCII.GetString(
                Encoding.Convert(
                    Encoding.UTF8,
                    Encoding.GetEncoding(
                        Encoding.ASCII.EncodingName,
                        new EncoderReplacementFallback("_"),
                        new DecoderExceptionFallback()
                        ),
                    Encoding.UTF8.GetBytes(sanitized)
                )
            );
            return asAscii.Replace(';', ' ');
        }
        [HttpGet("Video/{id}")]
        public async
        Task<FileStreamResult> DownloadAsync(string id)
        {
            var YT = new YoutubeClient();
            var videoname0 = await YT.Videos.GetAsync(id);


            var strs = await YT.Videos.Streams.GetManifestAsync(id);
            var high = strs.GetMuxedStreams().GetWithHighestVideoQuality();
            string sanitized = fixstr(videoname0.Title);

            return File(YT.Videos.Streams.GetAsync(high).Result, $"video/{high.Container.Name}", $"{sanitized}.{high.Container.Name}", true);
        }

        [HttpGet("VideoHigh/{id}")]
        public async Task<FileStreamResult> DownloadOnlyVideoAsync(string id)
        {
            var YT = new YoutubeClient();
            var videoname0 = await YT.Videos.GetAsync(id);


            string sanitized = fixstr(videoname0.Title);
            var strs = await YT.Videos.Streams.GetManifestAsync(id);
            var high = strs.GetVideoStreams().GetWithHighestVideoQuality();


            return File(YT.Videos.Streams.GetAsync(high).Result, $"video/{high.Container.Name}", $"{sanitized}.{high.Container.Name}", true);
        }
        [HttpGet("Audio/{id}")]
        public async Task<FileStreamResult> DownloadAudioAsync(string id)
        {
            var YT = new YoutubeClient();
            var videoname0 = await YT.Videos.GetAsync(id);


            string sanitized = fixstr(videoname0.Title);
            var strs = await YT.Videos.Streams.GetManifestAsync(id);
            var high = strs.GetAudioOnlyStreams().GetWithHighestBitrate();


            return File(YT.Videos.Streams.GetAsync(high).Result, $"audio/{high.Container.Name}", $"{sanitized}.{high.Container.Name}", true);

        }

        [HttpGet("Search/{id}")]
        public async Task<IActionResult> SearchAsync(string id)
        {
            var YT = new YoutubeClient();
              string s = "";
            await foreach(var v in YT.Search.GetVideosAsync(id))
            {
                 s += $"{v.Id}\n";
            }
            
            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "query.txt", true);
        }
        [HttpGet("ChannelNew2/{date}/{id}")]
        public async Task<IActionResult> NewUser2VideosAsync(string date,string id)
        {
            var YT = new YoutubeClient();

            var vids = ChannelIsValid(id) ? id : (await YT.Channels.GetByUserAsync(id)).Id.ToString();
    
            int videos = 0;
            string s = "";
             await foreach(var v in YT.Channels.GetUploadsAsync(vids))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

             }
             

            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }/*
        public async Task<IActionResult> NewUser2VideosAsync(string date, string id)
        {
            var YT = new YoutubeClient();
         var vids = ChannelIsValid(id) ? new ChannelId(id) : (await YT.Channels.GetByUserAsync(id)).Id;
            var ien = YT.Channels.GetUploadsAsync(vids);
            var vids2 = await ien.ToListAsync();
            int videos = 0;
            string s = "";
            foreach (YoutubeExplode.Playlists.PlaylistVideo v in vids2)
            {
                if (v.UploadDate.Date >= new DateTime(int.Parse(date.Split("-")[0]), int.Parse(date.Split("-")[1]), int.Parse(date.Split("-")[2])))
                {


                    var fileName = v.Title;

                     string sanitized = fixstr(fileName).Replace(' ','*');

                    s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Replace(" ", "-").Length, 439))} {v.Engagement.LikeCount} {v.Engagement.DislikeCount} {v.Engagement.ViewCount} {v.UploadDate.ToString("MM/dd/yyyy")} {v.Duration.Hours}:{v.Duration.Minutes}:{v.Duration.Seconds} ENDLINE\n";
                    videos++;

                } }


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
            return await User2VideosAsync(id);
        }*/
        [HttpGet("Channel2/{id}")]
        public async Task<IActionResult> User2VideosAsync(string id)
        {
            var YT = new YoutubeClient();

            var vids = ChannelIsValid(id) ? id : (await YT.Channels.GetByUserAsync(id)).Id.ToString();
           
            int videos = 0;
            string s = "";
              await foreach(var v in YT.Channels.GetUploadsAsync(vids))
            {
                
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992  ENDLINE\n";
                videos++;

            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        [HttpGet("User/{id}")]
        public async Task<IActionResult> UserVideosAsync(string id)
        {
            var YT = new YoutubeClient();
          
            
            var vids = await YT.Channels.GetByUserAsync(id);
 
          
            int videos = 0;
            string s = "";
            await foreach(var v in YT.Channels.GetUploadsAsync(vids.Id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        [HttpGet("UserNew/{date}/{id}")]
        public async Task<IActionResult> NewUserVideosAsync(string date,string id)
        {
            var YT = new YoutubeClient();

            var vids = await YT.Channels.GetByUserAsync(id);
           
            int videos = 0;
            string s = "";
            await foreach(var v in YT.Channels.GetUploadsAsync(vids.Id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        /*
        public async Task<IActionResult> NewUserVideosAsync(string date, string id)
        {
            var YT = new YoutubeClient();
            var vids = await YT.Channels.GetByUserAsync(id);
            var ien = YT.Channels.GetUploadsAsync(vids.Id);
            var vids2 = await ien.ToListAsync();
            int videos = 0;
            string s = "";
            foreach (var v in vids2)
            {
                if (v.UploadDate.Date >= new DateTime(int.Parse(date.Split("-")[0]), int.Parse(date.Split("-")[1]), int.Parse(date.Split("-")[2])))
                {


                    var fileName = v.Title;

                     string sanitized = fixstr(fileName).Replace(' ','*');

                    s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Replace(" ", "-").Length, 439))} {v.Engagement.LikeCount} {v.Engagement.DislikeCount} {v.Engagement.ViewCount} {v.UploadDate.ToString("MM/dd/yyyy")} {v.Duration.Hours}:{v.Duration.Minutes}:{v.Duration.Seconds} ENDLINE\n";
                    videos++;

                } }


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
            
            return await UserVideosAsync(id);
        }*/
        [HttpGet("Channel/{id}")]
        public async Task<IActionResult> ChannelVideosAsync(string id)
        {
            var YT = new YoutubeClient();


           
           
            int videos = 0;
            string s = "";
            await foreach(var v in YT.Channels.GetUploadsAsync(id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        [HttpGet("ChannelNew/{date}/{id}")]
        public async Task<IActionResult> NewChannelVideosAsync(string date,string id)
        {
            var YT = new YoutubeClient();


           
          
            int videos = 0;
            string s = "";
             await foreach (YoutubeExplode.Playlists.PlaylistVideo v in  YT.Channels.GetUploadsAsync(id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.ChannelTitle.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

            }


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);

        }
        /* public async Task<IActionResult> NewChannelVideosAsync(string date, string id)
         {
             var YT = new YoutubeClient();

             var ien = YT.Channels.GetUploadsAsync(id);
             var vids2 = await ien.ToListAsync();

             int videos = 0;
             string s = "";
             foreach (var v in vids2)
             {
                 if (v.UploadDate.Date >= new DateTime(int.Parse(date.Split("-")[0]), int.Parse(date.Split("-")[1]), int.Parse(date.Split("-")[2])))
                 {


                     var fileName = v.Title;
  string sanitized = fixstr(fileName).Replace(' ','*');

                     s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Replace(" ", "-").Length, 439))} {v.Engagement.LikeCount} {v.Engagement.DislikeCount} {v.Engagement.ViewCount} {v.UploadDate.ToString("MM/dd/yyyy")} {v.Duration.Hours}:{v.Duration.Minutes}:{v.Duration.Seconds} ENDLINE\n";
                     videos++;

                 }
             }


             return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);

             return await ChannelVideosAsync(id);
         }*/
        [HttpGet("searchinfo/{id}")]
        public async Task<IActionResult> SearchInfoAsync(string id)
        {
            var YT = new YoutubeClient();
            
            int videos = 0;
            string s = "";
            await foreach(var v in YT.Search.GetVideosAsync(id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
                videos++;

            };
            


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        [HttpGet("Playlist/{id}")]
        public async Task<IActionResult> PlaylistAsync(string id)
        {
            var YT = new YoutubeClient();
           
            string s = "";
            await foreach(var v in  YT.Search.GetVideosAsync(id))
            {
                s += $"{v.Id}\n";
            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "query.txt", true);
        }
        [HttpGet("playlistinfo/{id}")]
        public async Task<IActionResult> PlaylistInfoAsync(string id)
        {
            var YT = new YoutubeClient();
        
           
            string s = "";

            await foreach(var v in YT.Playlists.GetVideosAsync(id))
            {
                
                var fileName = v.Title;


                string sanitized = fixstr(fileName).Replace(' ', '*');

                s += $"{v.Id} {sanitized.Substring(0, Math.Min(sanitized.Length, 439))} {v.Author.Title.Replace("*", "_").Replace(" ", "*").Substring(0, Math.Min(v.Author.Title.Replace(" ", "-").Length, 439))} {0} {0} 0 8/20/1992 ENDLINE\n";
               

            };


            return File(ASCIIEncoding.Default.GetBytes(s), "text/plain", "info.txt", true);
        }
        [HttpGet("Info/{id}")]
        public async Task<IActionResult> InfoAsync(string id)
        {
            var YT = new YoutubeClient();
            var vids = await YT.Videos.GetAsync(id);



            return File(ASCIIEncoding.Default.GetBytes($"{vids.Title}\nhttps://i.ytimg.com/vi/{id}/default.jpg\n{vids.Author}"), "text/plain", "info.txt", true);
        }
        [HttpGet("jpg/{id}")]
        public async Task<IActionResult> Jpg(string id)
        {
            
            return Redirect($"https://i.ytimg.com/vi/{id}/default.jpg");
        }





        [HttpGet("ConvertString/{id}/{prefix}")]
        public async Task<IActionResult> REDIR(string id, string prefix)
        {
            try{
            VideoId v=id;
            string newid = v.ToString();

            return Redirect(prefix + newid);
            }catch(Exception)
            {
                return NotFound("nope not avail");
            }
        }
        [HttpGet("Descript/{id}")]
        public async Task<IActionResult> DescAsync(string id)
        {
            var YT = new YoutubeClient();
            var vids = await YT.Videos.GetAsync(id);



            return File(ASCIIEncoding.Default.GetBytes(vids.Description), "text/plain", "desc.txt");
        }

      
    }

}




