import requests
from bs4 import BeautifulSoup
import re
import cssutils
import logging
from urllib.parse import urljoin
import tinycss2

# Suppress cssutils warnings
cssutils.log.setLevel(logging.CRITICAL)

def extract_all_css(url):
    # Fetch the webpage content
    response = requests.get(url)
    soup = BeautifulSoup(response.text, 'html.parser')
    
    # Extract inline styles
    inline_styles = ' '.join([tag['style'] for tag in soup.find_all(attrs={'style': True})])
    
    # Extract embedded styles
    embedded_styles = ' '.join([style.string for style in soup.find_all('style')])
    
    # Extract external stylesheet URLs
    stylesheet_urls = [link['href'] for link in soup.find_all('link', rel='stylesheet')]
    
    # Fetch and concatenate external stylesheets
    external_styles = ''
    for stylesheet_url in stylesheet_urls:
        absolute_url = urljoin(url, stylesheet_url)
        try:
            external_styles += requests.get(absolute_url).text
        except:
            print(f"Failed to fetch stylesheet: {absolute_url}")
    
    # Combine all CSS
    all_css = inline_styles + ' ' + embedded_styles + ' ' + external_styles
    return all_css

def extract_relevant_css(all_css):
    relevant_properties = {
        'background': [
            r'background(?:-color)?',
            r'background-image',
            r'background:\s*[^;]+',
        ],
        'button': [
            r'(?:button|\.btn|\[type=(\'|")(?:button|submit)\1\]|\.button|a\.)',
            r'input\[type=(\'|")(?:button|submit)\1\]',
            r'--.*?(?:btn|button)',
            r'\.cta',
            r'\.primary',
            r'\.secondary',
            r'\.action',
        ],
        'text': [
            r'color',
            r'opacity',
        ],
        'font': [
            r'font(?:-family|-size|-weight|-style)?',
            r'text-decoration',
            r'text-transform',
            r'line-height',
            r'letter-spacing',
        ],
        'body': [
            r'body',
            r'html',
        ],
        'variables': [
            r'--.*?(?:color|font|bg|background|button|text)',
        ],
        'other': [
            r'box-shadow',
            r'(?:linear|radial)-gradient',
            r'border',
            r'outline',
        ]
    }
    
    # Combine all properties into a single regex pattern
    pattern = '|'.join([item for sublist in relevant_properties.values() for item in sublist])
    
    # Parse the CSS using tinycss2
    stylesheet = tinycss2.parse_stylesheet(all_css)
    
    relevant_css = []
    
    for rule in stylesheet:
        if rule.type == 'qualified-rule':
            selector = tinycss2.serialize(rule.prelude)
            declarations = tinycss2.parse_declaration_list(tinycss2.serialize(rule.content))
            
            relevant_styles = []
            for decl in declarations:
                if decl.type == 'declaration':
                    property_name = decl.lower_name
                    property_value = tinycss2.serialize(decl.value)
                    
                    if re.search(pattern, property_name, re.IGNORECASE) or \
                       re.search(pattern, f"{selector} {property_name}", re.IGNORECASE) or \
                       re.search(pattern, f"{property_name}: {property_value}", re.IGNORECASE):
                        relevant_styles.append(f"{property_name}: {property_value};")
            
            if relevant_styles:
                relevant_css.append(f"{selector} {{\n  " + "\n  ".join(relevant_styles) + "\n}")
    
    return "\n\n".join(relevant_css)

# Example usage
url = "https://ftu.edu.vn/"
all_css = extract_all_css(url)
relevant_css = extract_relevant_css(all_css)
print(relevant_css)
print(len(all_css))
print(len(relevant_css)) \n Đoạn code này nhằm từ 1 web url trích xuất được các dòng code liên quan đến background color, button color, text color và font style. Hiện tại với trang web url = "https://ftu.edu.vn/" đang thiếu thông tin về background color khiến cho việc phân tích sai. Hãy tối ưu lại code!