#!/usr/bin/env python3
"""
@coolhand.bsky.social

Because Fuck Fascists
Optionally exports sales and product details to CSV, and then deletes all products, including canceling subscriptions.

Date: 2023-11-15
"""

import requests
import json
import csv
import sys

# ----------------------------
# ASCII Art Banner & Dependencies Check
# ----------------------------
def print_banner():
    banner = '''
    ██████╗ ██╗   ██╗███╗   ███╗██████╗ ██╗██████╗ 
    ██╔════╝ ██║   ██║████╗ ████║██╔══██╗██║██╔══██╗
    ██║  ███╗██║   ██║██╔████╔██║██████╔╝██║██║  ██║
    ██║   ██║██║   ██║██║╚██╔╝██║██╔══██╗██║██║  ██║
    ╚██████╔╝╚██████╔╝██║ ╚═╝ ██║██║  ██║██║██████╔╝
     ╚═════╝  ╚═════╝ ╚═╝     ╚═╝╚═╝  ╚═╝╚═╝╚═════╝ 
    ================================================
           .:: BECAUSE FUCK FASCISTS ::.
    ================================================
    - Delete ALL products from Gumroad account
    - Export sales and product data to CSV
    - Burn it all down
    ================================================
    @coolhand.bsky.social | 2023-11-15
    '''
    print(banner)

def check_dependencies():
    try:
        import requests
    except ImportError:
        print("\n[!] Required package 'requests' not found")
        print("[+] Install required packages with:")
        print("    pip install requests\n")
        sys.exit(1)

# Call these functions at startup
print_banner()
check_dependencies()

# ----------------------------
# Configuration and Credentials
# ----------------------------
BASE_API_URL = "https://api.gumroad.com/v2"
LOG_FILE = "gumroad_api_log.txt"

def get_access_token():
    print("\nGumroad API Access Token Required")
    print("--------------------------------")
    print("To use this script, you need to create a Gumroad API access token:")
    print("1. Go to: https://gumroad.com/settings/advanced#application-form")
    print("2. Create a new application if you don't have one")
    print("3. Generate an access token for your application")
    print("4. Copy and paste the token below\n")
    
    token = input("Enter your Gumroad API access token: ").strip()
    if not token:
        print("Access token is required. Exiting...")
        sys.exit(1)
    return token

# ----------------------------
# Utility Functions and Error Handling
# ----------------------------
def log_output(text):
    with open(LOG_FILE, "a") as log_file:
        log_file.write(text + "\n")
    print(text)

def make_request(endpoint, method, data=None, access_token=None):
    url = f"{BASE_API_URL}/{endpoint}"
    headers = {
        "Authorization": f"Bearer {access_token}",
        "Content-Type": "application/json"
    }
    try:
        if method.upper() == "GET":
            response = requests.get(url, headers=headers, timeout=120)
        elif method.upper() == "POST":
            response = requests.post(url, headers=headers, json=data, timeout=120)
        elif method.upper() == "PUT":
            response = requests.put(url, headers=headers, json=data, timeout=120)
        elif method.upper() == "DELETE":
            response = requests.delete(url, headers=headers, timeout=120)
        else:
            log_output(f"Unsupported HTTP method: {method}")
            return None

        resp_json = response.json()
        # Check for success field; if not true, log error
        if not resp_json.get("success", False):
            log_output(f"Error Response: {json.dumps(resp_json)}")
            return None

        log_output(json.dumps(resp_json))
        return resp_json

    except Exception as e:
        log_output(f"Exception during API call: {e}")
        return None

# ----------------------------
# Main Functions
# ----------------------------
def delete_all_products(access_token):
    confirm = input("WARNING: This will delete ALL products. Proceed? (yes/no): ").strip()
    if confirm.lower() != "yes":
        log_output("Deletion aborted.")
        return

    # Offer to export sales data before deletion
    export_sales_choice = input("Would you like to export full sales data to CSV before deletion? (yes/no): ").strip()
    if export_sales_choice.lower() == "yes":
        export_sales_csv(access_token)

    # Offer to export product data before deletion
    export_products_choice = input("Would you like to export full product data to CSV before deletion? (yes/no): ").strip()
    if export_products_choice.lower() == "yes":
        export_products_csv(access_token)

    log_output("Fetching all products...")
    resp = make_request("products", "GET", access_token=access_token)
    if resp and "products" in resp:
        for prod in resp["products"]:
            prod_id = prod.get("id")
            log_output(f"Deleting Product ID: {prod_id}...")
            del_resp = make_request(f"products/{prod_id}", "DELETE", access_token=access_token)
            if del_resp:
                log_output(json.dumps(del_resp, indent=2))
    else:
        log_output("No products found to delete.")

def export_sales_csv(access_token):
    log_output("Exporting full sales data to CSV...")
    filename = input("Enter CSV filename (default: gumroad_export_sales.csv): ").strip()
    if not filename:
        filename = "gumroad_export_sales.csv"

    resp = make_request("sales", "GET", access_token=access_token)
    if not resp:
        log_output("No response from API.")
        return

    sales = resp.get("sales", [])
    if len(sales) == 0:
        with open(filename, "w", newline="") as csvfile:
            csvfile.write("No sales data found.")
        log_output(f"No sales exported; {filename} created with no data.")
        return

    # Use keys from first sale, sorted for consistency
    header_keys = sorted(sales[0].keys())
    with open(filename, "w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(header_keys)
        # Process pages
        page_key = None
        while True:
            endpoint = "sales" if not page_key else f"sales?page_key={page_key}"
            resp = make_request(endpoint, "GET", access_token=access_token)
            if resp and "sales" in resp:
                for sale in resp["sales"]:
                    # Sort values according to header_keys
                    row = [sale.get(key, "") for key in header_keys]
                    writer.writerow(row)
                page_key = resp.get("next_page_key")
                if not page_key or page_key == "null":
                    break
            else:
                break
    log_output(f"Sales exported to {filename}.")

def export_products_csv(access_token):
    log_output("Exporting full product data to CSV...")
    filename = input("Enter CSV filename (default: gumroad_export_products.csv): ").strip()
    if not filename:
        filename = "gumroad_export_products.csv"

    resp = make_request("products", "GET", access_token=access_token)
    if not resp:
        log_output("No response from API.")
        return

    products = resp.get("products", [])
    if len(products) == 0:
        with open(filename, "w", newline="") as csvfile:
            csvfile.write("No product data found.")
        log_output(f"No products exported; {filename} created with no data.")
        return

    header_keys = sorted(products[0].keys())
    with open(filename, "w", newline="") as csvfile:
        writer = csv.writer(csvfile)
        writer.writerow(header_keys)
        for prod in products:
            row = [prod.get(key, "") for key in header_keys]
            writer.writerow(row)
    log_output(f"Products exported to {filename}.")

# ----------------------------
# Main Interactive Loop
# ----------------------------
def main():
    # Get access token at the start
    access_token = get_access_token()
    
    while True:
        print("\nGumroad API Interactive Shell")
        print("1) Delete All Products")
        print("2) Export Sales to CSV")
        print("3) Export Products to CSV") 
        print("4) Exit")
        choice = input("Choose an option: ").strip()

        if choice == "1":
            delete_all_products(access_token)
        elif choice == "2":
            export_sales_csv(access_token)
        elif choice == "3":
            export_products_csv(access_token)
        elif choice == "4":
            log_output("Exiting...")
            sys.exit(0)
        else:
            log_output("Invalid option, please try again.")
        input("\nPress Enter to continue...")

if __name__ == '__main__':
    # Banner and dependency check are called at import time
    main()