#!/usr/bin/env python3
"""Parse GitHub Trending page using stdlib html.parser.

Uses approach: capture href in handle_starttag, accumulate h2 text in buffer,
finalize name+url only on </a> (not on </h2>). This avoids the
get_starttag_text() pitfall where that method returns the LAST start tag,
not the one matching the current end tag.

Outputs up to 20 valid repos to /tmp/trending_parsed.json.
"""
import json
from html.parser import HTMLParser

INPUT = "/tmp/gh_trending.html"
OUTPUT = "/tmp/trending_parsed.json"


class TrendingParser(HTMLParser):
    def __init__(self):
        super().__init__()
        self.items = []
        self.in_article = False
        self.cur = None
        self.capture = None   # 'h2', 'desc', 'lang', 'stars'
        self.buf = []

    def handle_starttag(self, tag, attrs):
        d = dict(attrs)
        if tag == 'article' and d.get('class', '').startswith('Box-row'):
            self.in_article = True
            self.cur = {}
        if not self.in_article:
            return

        if tag == 'h2':
            self.capture = 'h2'
            self.buf = []
            self.cur['url'] = ''
        elif tag == 'a' and self.capture == 'h2':
            # Capture repo URL from the <a> start tag inside h2
            href = d.get('href', '')
            if href:
                self.cur['url'] = 'https://github.com' + href
        elif tag == 'p' and self.cur.get('description') is None and 'col-9' in d.get('class', ''):
            self.capture = 'desc'
            self.buf = []
        elif tag == 'span' and d.get('itemprop') == 'programmingLanguage':
            self.capture = 'lang'
            self.buf = []
        elif tag == 'a' and d.get('href', '').endswith('/stargazers'):
            self.capture = 'stars'
            self.buf = []

    def handle_data(self, data):
        if self.capture:
            self.buf.append(data)

    def handle_endtag(self, tag):
        if not self.in_article:
            return

        # While inside h2: only finalize name+url on </a>, ignore </span> etc.
        if self.capture == 'h2':
            if tag == 'a':
                val = ' '.join(''.join(self.buf).split())
                self.cur['name'] = val.replace(' / ', '/').strip()
                self.capture = None
                self.buf = []
            return

        if tag in {'p', 'span', 'a'} and self.capture:
            val = ' '.join(''.join(self.buf).split())
            if self.capture == 'desc':
                self.cur['description'] = val
            elif self.capture == 'lang':
                self.cur['language'] = val
            elif self.capture == 'stars':
                self.cur['stars'] = val.replace(',', '')
            self.capture = None
            self.buf = []

        elif tag == 'article':
            if self.cur and self.cur.get('url') and 'sponsors/' not in self.cur['url']:
                self.items.append(self.cur)
            self.in_article = False
            self.cur = None
            self.capture = None
            self.buf = []


def main():
    with open(INPUT, 'r', encoding='utf-8', errors='ignore') as f:
        html = f.read()

    parser = TrendingParser()
    parser.feed(html)
    parser.close()

    out = []
    for x in parser.items:
        if len(out) >= 20:
            break
        out.append({
            'full_name': x.get('name', '').replace(' / ', '/'),
            'url': x.get('url', ''),
            'language': x.get('language') or 'N/A',
            'stars': x.get('stars') or '0',
        })

    with open(OUTPUT, 'w', encoding='utf-8') as f:
        json.dump(out, f, indent=2, ensure_ascii=False)

    print(f"Parsed {len(out)} repos -> {OUTPUT}")


if __name__ == '__main__':
    main()
