# -*- coding: utf-8 -*-
from urllib.parse import urlparse, parse_qs
import json
import re

import requests
from bs4 import BeautifulSoup
import pandas as pd
from idebug import *


__all__ = [
    'YouTubeMusic',
]


class Y2MateBrowser:

    def __init__(self, title=None):
        self.download_path = 'C:/Users/innovata/Music'
        self._title = title

    @funcIdentity
    def search(self, url):
        # url: 유투브 영상 URL
        # PartGubun('search')
        o = urlparse('https://suggestqueries.google.com/complete/search?jsonp=jQuery340004144273343421623_1635056106020&q=https%3A%2F%2Fyoutu.be%2Fc9h5VloOhCc%3Flist%3DTLPQMjQxMDIwMjEgBM7O0V7Bvg&hl=en&ds=yt&client=youtube&_=1635056106021')
        # print(o)
        qs = parse_qs(o.query)
        # pp.pprint(qs)
        o = o._replace(query='')
        # print(o)

        # 입력받은 유투브URL을 qs객체에 업데이트
        self.yt_url = url
        yt = urlparse(self.yt_url)
        # print(yt)
        param = {k:v[0] for k,v in qs.items()}
        param['q'] = self.yt_url
        # pp.pprint(param)
        # print('geturl:', o.geturl())
        r = requests.get(o.geturl(), param)
        # dbg.dict(r)
        # print(r.text, type(r.text))

    @funcIdentity
    def ajax(self):
        # PartGubun('Ajax')
        url = 'https://www.y2mate.com/mates/en105/analyze/ajax'
        qs = parse_qs('url=https%3A%2F%2Fyoutu.be%2FagnV2YjuzSM%3Flist%3DPLP9YOa5MTwu06to2NmlacATe-zEXHUOTw&q_auto=0&ajax=1')
        # print(qs)
        data = {k:v[0] for k,v in qs.items()}
        data['url'] = self.yt_url
        r = requests.post(url, data)
        # dbg.dict(r)

        # SectionGubun('Response-Data')
        d = json.loads(r.text)
        # pp.pprint(d)

        # SectionGubun('HTML파싱')
        soup = BeautifulSoup(d['result'], 'html.parser')
        # print(soup.prettify())

        self._title = soup.find('div', class_='caption text-left').b.get_text().strip()
        # print('title:', self._title)

        # print(soup.input.attrs)
        self.data_id = soup.input.attrs['data-id']

        # SectionGubun('KData 추출')
        s = soup.find('script', attrs={'type':'text/javascript'})
        # print(s.get_text())
        li = s.get_text().split(';')
        li = [e.strip() for e in li if len(e.strip()) > 0]
        d = {}
        for e in li:
            m = re.search('var\s([a-z_]+)\s=\s"(.+)"', e)
            d.update({m[1]:m[2]})
        # pp.pprint(d)
        self.KData = d

    @property
    def title(self):
        # title = self.KData['k_data_vtitle']
        title = self._title
        # [Windows|MacOS] 에서 지원하지 않는 파일명에 대한 청소
        title = re.sub('[\s]+', repl=' ', string=title)
        title = re.sub('[:\|\?\*"\<\>/]+', repl='#', string=title)
        # print('title:', title)
        return title

    @funcIdentity
    def fetch_img(self):
        # PartGubun('이미지 저장')
        url = f'https://i.ytimg.com/vi/{self.data_id}/0.jpg'
        r = requests.get(url)
        # dbg.dict(r)
        fpath = f"{self.download_path}/{self.title}.jpg"
        print('fpath:', fpath)
        with open(fpath, 'wb') as fd:
            for chunk in r.iter_content(chunk_size=128):
                fd.write(chunk)
        fd.close()
        logger.info(f'{self} | Done. FilePath: {fpath}')

    @funcIdentity
    def xc(self):
        # PartGubun('xc')
        r = requests.get('https://habeglee.net/s9np/xc')
        # dbg.dict(r)
        d = json.loads(r.text)
        # pp.pprint(d)

    @funcIdentity
    def convert(self):
        # PartGubun('convert')
        qs = parse_qs('type=youtube&_id=5e9b86ec7527f838068b4591&v_id=agnV2YjuzSM&ajax=1&token=&ftype=mp3&fquality=128')
        qs['_id'] = self.KData['k__id']
        qs['v_id'] = self.KData['k_data_vid']
        r = requests.post('https://www.y2mate.com/mates/convert', data=qs)
        # dbg.dict(r)
        d = json.loads(r.text)

        # SectionGubun('HTML파싱')
        soup = BeautifulSoup(d['result'], 'html.parser')
        # print(soup.prettify())
        href = soup.find('a').attrs['href']
        # print('href:', href)
        o = urlparse(href)
        # print(o)
        self.download_url = href

    @funcIdentity
    def download(self):
        # PartGubun('파일 다운로드')
        r = requests.get(self.download_url)
        # dbg.dict(r)
        fpath = f"{self.download_path}/{self.title}.mp3"
        with open(fpath, 'wb') as fd:
            for chunk in r.iter_content(chunk_size=128):
                fd.write(chunk)
        fd.close()
        logger.info(f'{self} | Done. FilePath: {fpath}')

    def clean_fpath(self, fpath):
        return fpath

    @funcIdentity
    def get_mp3(self, url):
        self.search(url)
        self.ajax()
        self.fetch_img()
        self.convert()
        self.download()

class YouTubeBrowser:

    def __init__(self):
        pass

    def get(self, url):
        r = requests.get(url)
        # dbg.dict(r)
        # SectionGubun('HTML파싱')
        soup = BeautifulSoup(r.text, 'html.parser')
        # print(soup.prettify())

        s = soup.find('script', string=re.compile('var ytInitialData'))
        # print(s.prettify())

        txt = s.get_text().strip()
        txt = re.sub('^var ytInitialData = ', repl='', string=txt)
        txt = re.sub(';$', repl='', string=txt)
        txt = re.sub('\s+', repl=' ', string=txt)
        # print(txt)

        d = json.loads(txt)
        d = d['contents']['twoColumnWatchNextResults']['playlist']['playlist']
        # print('len(d):', len(d))
        # print('d.keys:', list(d.keys()))

        self._playlistId = d['playlistId']
        self._playlistTitle = d['title']
        d = d['contents']
        # print('type(d):', type(d), isinstance(d, list), len(d))

        # SectionGubun('JSON_Normalize')
        data = []
        for e in d:
            data.append(e['playlistPanelVideoRenderer'])
        df = pd.json_normalize(data)
        # pp.pprint(sorted(df.columns))

        for c in sorted(df.columns):
            # SectionGubun(c)
            # print(df[c])
            if c == 'videoId':
                self._videoIds = list(df[c])
            elif c == 'title.simpleText':
                pp.pprint(list(df[c]))

    @property
    def PlayListId(self):
        return self._playlistId

    @property
    def PlayListTitle(self):
        return self._playlistTitle

    @property
    def VideoIds(self):
        return self._videoIds

class YouTubeMusic:

    def __init__(self):
        self.youtube = YouTubeBrowser()
        self.y2mate = Y2MateBrowser()

    @funcIdentity
    def download_playlist(self, url):
        # url: 유투브 플레이리스트 URL
        self.youtube.get(url)
        for videoId in self.youtube.VideoIds:
            url = f'https://youtu.be/{videoId}?list={self.youtube.PlayListId}'
            self.y2mate.get_mp3(url)
        logger.info(f'{self} | Done.')

    @funcIdentity
    def download_one(self, url):
        # url: 유투브 비디오 URL
        self.y2mate.get_mp3(url)
        logger.info(f'{self} | Done.')
