#!/usr/bin/env python3
# /// script
# requires-python = ">=3.10"
# dependencies = ["pandas", "pyarrow", "requests", "joblib", "beautifulsoup4", "openpyxl"]
# ///

import re

import joblib
import pandas as pd
import requests
from bs4 import BeautifulSoup

memory = joblib.Memory(".cache", verbose=0)


@memory.cache
def fetch_page(url):
    r = requests.get(url)
    r.raise_for_status()
    return r.text


def parse_tag_actions(soup) -> list[dict]:
    # Extract service prefix
    prefix_match = soup.find(string=re.compile(r"service prefix:"))
    if not prefix_match:
        return []

    prefix_code = prefix_match.find_next("code", class_="code")
    if not prefix_code:
        return []
    service_prefix = prefix_code.get_text(strip=True)

    # Find actions table (after h2 with id ending in -actions-as-permissions)
    actions_heading = soup.find("h2", id=re.compile(r"-actions-as-permissions$"))
    if not actions_heading:
        return []

    table = actions_heading.find_next("table")
    if not table:
        return []

    results = []
    current_action = None
    current_access_level = None

    for row in table.find_all("tr"):
        cells = row.find_all("td")
        if not cells:
            continue

        first_cell = cells[0]

        # Check if this row starts a new action (has id attribute)
        if first_cell.get("id"):
            # New action row
            link = first_cell.find("a")
            action_name = link.get_text(strip=True) if link else first_cell.get_text(strip=True)

            # Check if action contains "Tag"
            if "Tag" in action_name:
                current_action = action_name
                # Access level is in 3rd column (index 2)
                current_access_level = cells[2].get_text(strip=True) if len(cells) > 2 else ""
            else:
                current_action = None
                current_access_level = None

        # If we're tracking a Tag action, extract resource types
        if current_action:
            # Resource types column is 4th (index 3) for first row, or 1st (index 0) for continuation rows
            if first_cell.get("id"):
                resource_cell = cells[3] if len(cells) > 3 else None
            else:
                resource_cell = cells[0] if cells else None

            if resource_cell:
                for link in resource_cell.find_all("a"):
                    resource_type = link.get_text(strip=True)
                    # Remove trailing * (required marker)
                    resource_type = resource_type.rstrip("*")
                    if resource_type:
                        results.append({
                            "service_prefix": service_prefix,
                            "action_name": current_action,
                            "access_level": current_access_level,
                            "resource_type": resource_type,
                        })

    return results


def main():
    services_df = pd.read_parquet("aws_services.parquet")

    all_actions = []
    for _, row in services_df.iterrows():
        html = fetch_page(row["href"])
        soup = BeautifulSoup(html, "html.parser")
        actions = parse_tag_actions(soup)
        all_actions.extend(actions)
        print(f"{row['slug']}: {len(actions)} tag actions")

    df = pd.DataFrame(all_actions)
    df.to_parquet("aws_tag_actions.parquet", index=False)
    df.to_excel("aws_tag_actions.xlsx", index=False)
    print(f"\nWrote {len(df)} tag actions to aws_tag_actions.parquet and aws_tag_actions.xlsx")


if __name__ == "__main__":
    main()
