import requests
import csv
import time
import re
import os
from bs4 import BeautifulSoup
from urllib.parse import urlparse
import sys

# API Keys
WHOIS_API_KEY = "at_Z00D3inE7gTP68vXKKDeNFqd1Ndxg"
GOOGLE_API_KEY = "AIzaSyCl9sInU5WkCS43H3L8Pzj88GHGeiePC88"
CUSTOM_SEARCH_ID = "77f3646e1ed644183"
PLACES_API_KEY = "AIzaSyCl9sInU5WkCS43H3L8Pzj88GHGeiePC88"

# Input and output file paths
INPUT_CSV = "security_headers_results.csv"

if len(sys.argv) < 2:
    print("❌ Error: No grade provided. Please specify a grade to look up.")
    sys.exit(1)
GRADE_TO_LOOKUP = sys.argv[1]
OUTPUT_CSV = f"business_lookup_{GRADE_TO_LOOKUP.lower()}_results.csv"

# Mapping of Google Places "types" to more useful industry names
INDUSTRY_MAPPING = {
    "point_of_interest": "General Business",
    "establishment": "Business Entity",
    "school": "Education",
    "hospital": "Healthcare",
    "lawyer": "Legal Services",
    "restaurant": "Food & Beverage",
    "finance": "Finance & Investment",
    "real_estate_agency": "Real Estate",
    "supermarket": "Retail",
    "gym": "Fitness & Wellness",
    "lodging": "Hospitality",
    "accounting": "Accounting",
    "dentist": "Dental Services",
    "beauty_salon": "Beauty & Personal Care",
    "doctor": "Medical Services",
    "child_care": "Childcare Services",
    "day_care": "Childcare Services",
    "university": "Higher Education",
    "store": "Retail",
}

# Service vs Product classification
SERVICE_TYPES = {"lawyer", "hospital", "doctor", "dentist", "accounting", "child_care", "beauty_salon", "gym", "finance"}
PRODUCT_TYPES = {"store", "supermarket", "real_estate_agency", "restaurant"}

# Function to extract only the Australian state from an address
def extract_state(address):
    state_pattern = re.compile(r"\b(NSW|VIC|QLD|WA|SA|TAS|ACT|NT)\b")
    match = state_pattern.search(address)
    return match.group(0) if match else "Not Found"

# Function to improve industry classification
def get_industry_from_types(types_list):
    for t in types_list:
        if t in INDUSTRY_MAPPING:
            return INDUSTRY_MAPPING[t]
    return ", ".join(types_list) if types_list else "Not Found"

# Function to determine if business is service-based or product-based
def get_business_type(types_list):
    if any(t in SERVICE_TYPES for t in types_list):
        return "Service-Based"
    elif any(t in PRODUCT_TYPES for t in types_list):
        return "Product-Based"
    return "Unknown"

# Function to extract email from a website
def extract_email_from_website(domain):
    try:
        response = requests.get(f"http://{domain}", timeout=5)
        if response.status_code == 200:
            emails = re.findall(r"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+", response.text)
            return emails[0] if emails else "Not Found"
    except requests.RequestException:
        pass
    return "Not Found"

# Function to get business details from Google Places API
def get_business_details_from_google_places(domain):
    search_url = f"https://maps.googleapis.com/maps/api/place/findplacefromtext/json?input={domain}&inputtype=textquery&fields=name,formatted_address,types&key={PLACES_API_KEY}"
    response = requests.get(search_url)
    data = response.json()
    
    if "candidates" in data and data["candidates"]:
        business_name = data["candidates"][0].get("name", "Not Found")
        address = data["candidates"][0].get("formatted_address", "Not Found")
        state = extract_state(address)
        industry = get_industry_from_types(data["candidates"][0].get("types", []))
        business_type = get_business_type(data["candidates"][0].get("types", []))
        return business_name, state, industry, business_type
    
    return "Not Found", "Not Found", "Not Found", "Unknown"

# Function to check existing records and resume
existing_domains = set()
total_existing_records = 0
state_counts = {}
total_full_match = total_partial_match = total_no_match = 0
if os.path.exists(OUTPUT_CSV):
    with open(OUTPUT_CSV, "r") as outfile:
        reader = csv.reader(outfile)
        next(reader)  # Skip header
        for row in reader:
            existing_domains.add(row[0])  # Store processed domains
            total_existing_records += 1
            state = row[2]
            if state:
                state_counts[state] = state_counts.get(state, 0) + 1
            
            if row[1] != "Not Found" and row[2] != "Not Found" and row[3] != "Not Found":
                total_full_match += 1
            elif row[1] == "Not Found" and row[2] == "Not Found" and row[3] == "Not Found":
                total_no_match += 1
            else:
                total_partial_match += 1

# Function to process domains
def process_domains():
    global total_full_match, total_partial_match, total_no_match  # Ensure variables are accessible
    
    total_records = 0

    with open(INPUT_CSV, "r") as infile:
        reader = csv.reader(infile)
        data = list(reader)

    # Count records to process
    total_records = sum(1 for row in data if row[1] == GRADE_TO_LOOKUP and row[0] not in existing_domains)
    print(f"📊 Total new records to process: {total_records}")
    print(f"📊 Total records already processed: {total_existing_records}")
    print(f"📊 Total combined records: {total_records + total_existing_records}")
    
    if total_records == 0:
        print(f"❌ No new records found for grade {GRADE_TO_LOOKUP}. Showing summary:")
    
    with open(OUTPUT_CSV, "a", newline="") as outfile:
        writer = csv.writer(outfile)
        if os.stat(OUTPUT_CSV).st_size == 0:
            writer.writerow(["Domain", "Business Name", "State", "Industry", "Business Type", "Email", "Grade", "Security Headers Report"])
        
        remaining_records = total_records
        for index, row in enumerate(data, start=1):
            domain = row[0]
            grade = row[1]

            if grade != GRADE_TO_LOOKUP or domain in existing_domains:
                continue
            
            business_name, state, industry, business_type = get_business_details_from_google_places(domain)
            email = extract_email_from_website(domain)
            security_headers_url = f"https://securityheaders.com/?q={domain}&followRedirects=on"
            
            writer.writerow([domain, business_name, state, industry, business_type, email, grade, security_headers_url])
            existing_domains.add(domain)
            remaining_records -= 1

            if state != "Not Found":
                state_counts[state] = state_counts.get(state, 0) + 1
            
            if business_name != "Not Found" and state != "Not Found" and industry != "Not Found":
                status = "✅ Full Match"
                total_full_match += 1
            elif business_name == "Not Found" and state == "Not Found" and industry == "Not Found":
                status = "❌ No Match"
                total_no_match += 1
            else:
                status = "⚠️ Partial Match"
                total_partial_match += 1
            
            print(f"{domain} - {state} - {status} | {remaining_records} remaining")
            
            if index % 100 == 0:
                print(f"✅ Progress saved at {index} records. {remaining_records} remaining.")
    
    print(f"✅ Lookup completed. Results extracted from {OUTPUT_CSV}")
    print(f"📊 Total records looked up: {total_full_match + total_partial_match + total_no_match}")
    print(f"✅ Total records fully matched: {total_full_match}")
    print(f"⚠️ Total records partially matched: {total_partial_match}")
    print(f"❌ Total records not matched: {total_no_match}")
    if not state_counts:
        print("🏛 Breakdown of records per state: No data available.")
    else:
        for state, count in state_counts.items():
            print(f"🏛 {state}: {count} records")
    
    sys.exit(0)

# Run the script
if __name__ == "__main__":
    process_domains()
