from bs4 import BeautifulSoup, Tag
import copy

from page_scraper.core.utils import exclude_tags, process_text, canonical_url, process_link, classify_url, clear_text
from page_scraper.entities.models import PageHeading, UrlContext
from page_scraper.infrastructure.fetcher import HttpFetcher

TAGS_TO_EXCLUDE = ("[class*=comment], [id*=comment], [id*=sidebar], [id*=footer],"
                          "nav, footer, aside, menu, sidebar, head, script")
HEADINGS = "h1,h2,h3,h4,h5,h6"

fetcher = HttpFetcher()

VIDEO_PROVIDERS = (
    "youtube.com",
    "youtu.be",
    "vimeo.com",
    "aparat.com",
    "dailymotion.com",
)

AUDIO_PROVIDERS = (
    "spotify.com",
    "soundcloud.com",
    "podcasts.google.com",
    "anchor.fm",
)

def get_headings(soup: BeautifulSoup) -> list[Tag]:
    cleaned = copy.copy(soup)
    exclude_tags(cleaned, TAGS_TO_EXCLUDE)
    return [
        h for h in cleaned.select(HEADINGS)
    ]

def get_clean_tags(soup: BeautifulSoup, tag_string:str) -> list[Tag]:
    cleaned = copy.copy(soup)
    exclude_tags(cleaned, TAGS_TO_EXCLUDE)
    return [
        i for i in cleaned.select(tag_string)
    ]

def get_media(soup: BeautifulSoup, media_tag:str) -> list[Tag]:
    cleaned = copy.copy(soup)
    exclude_tags(cleaned, TAGS_TO_EXCLUDE)
    return [
        i for i in cleaned.select(media_tag)
    ]

def create_tag_dict(tag:Tag) -> dict:
    tag_name = tag.name
    tag_text = process_text(tag)
    return {"name": tag_name, "text": tag_text}

def process_headings(tags:list[Tag]) -> list[PageHeading]:
    result = []
    for tag in tags:
        tag_dict = create_tag_dict(tag)
        page_heading = PageHeading(tag_dict.get("name"),tag_dict.get("text"))
        result.append(page_heading)
    return result

def process_alt(tag:Tag)->str | None:
    return clear_text(tag.get("alt")) if tag.get("alt") else None

def get_media_src(tag:Tag) -> str|None:
    return tag.get("src",None)

def process_media_tag_with_url(url:str, base:str) -> UrlContext:
    address = canonical_url(url, base)
    classified_url = classify_url(address)
    if classified_url == "web":
        response = fetcher.head(address)
        return process_link(url, response=response)
    else:
        return process_link(url, url_type=classified_url)


def process_image(tags:list[Tag], base:str)->list[UrlContext]:
    result = []
    for tag in tags:
        src = get_media_src(tag)
        if not src:
            continue

        data = process_media_tag_with_url(src, base)

        if not data:
            continue

        data.text = process_alt(tag)

        data.position = "IMAGE_TAG"

        result.append(data)

    return result

def process_media_tags(tags:list[Tag], base:str, tag_type:str) -> list[UrlContext]:
    result = []

    for tag in tags:
        if get_media_src(tag):

            data = process_media_tag_with_url(get_media_src(tag), base)

            if not data:
                continue

            data.position = tag_type

            result.append(data)

            continue

        for source in tag.find_all("source"):
            if get_media_src(source):
                data = process_media_tag_with_url(get_media_src(source), base)

                if not data:
                    continue

                data.position = tag_type

                result.append(data)

    return result

def process_video_iframe(tags:list[Tag], base:str) -> list[UrlContext]:
    result = []
    for tag in tags:
        src = get_media_src(tag)
        if not src:
            continue

        if not any(provider in src for provider in VIDEO_PROVIDERS):
            continue

        data = process_media_tag_with_url(src, base)

        if not data:
            continue

        data.position = "VIDEO_IFRAME"

        result.append(data)

    return result

def process_video_embed(tags:list[Tag], base:str) -> list[UrlContext]:
    result = []
    for tag in tags:
        src = get_media_src(tag) or tag.get("data")
        if not src:
            continue

        data = process_media_tag_with_url(src, base)

        if not data:
            continue

        data.position = "VIDEO_EMBED"

        result.append(data)

    return result