import csv
import json
from google.cloud import bigquery

# Optional imports with error handling
try:
    import pandas as pd
except ImportError:
    pd = None

try:
    import gspread
    import google.auth
except ImportError:
    gspread = None

class PiExporter:
    @staticmethod
    def to_csv(data, filename):
        if not data:
            print("No data to export.")
            return
        
        if not filename.endswith('.csv'):
            filename += '.csv'
            
        keys = data[0].keys()
        with open(filename, 'w', newline='', encoding='utf-8') as f:
            writer = csv.DictWriter(f, fieldnames=keys)
            writer.writeheader()
            writer.writerows(data)
        print(f"Successfully saved {len(data)} rows to {filename}")

    @staticmethod
    def to_excel(data, filename):
        """Exports data to Excel. Requires pandas and openpyxl."""
        if pd is None:
            print("Error: Pandas not installed. Run: pip install pandas openpyxl")
            return
        if not data:
            print("No data to export.")
            return

        if not filename.endswith('.xlsx'):
            filename += '.xlsx'

        try:
            df = pd.DataFrame(data)
            df.to_excel(filename, index=False)
            print(f"Successfully saved {len(data)} rows to {filename}")
        except Exception as e:
            print(f"Excel Export Failed: {e}")

    @staticmethod
    def to_google_sheet(data, spreadsheet_name, tab_name="Sheet1"):
        """
        Exports to Google Sheet using the Filename (not ID).
        Uses the active Colab authentication.
        """
        if gspread is None:
            print("Error: gspread not installed. Run: pip install gspread google-auth")
            return
        if not data:
            print("No data to upload.")
            return

        print(f"Connecting to Google Sheet: '{spreadsheet_name}'...")

        try:
            # 1. Get Default Credentials (works with Colab auth.authenticate_user)
            creds, _ = google.auth.default()
            client = gspread.authorize(creds)

            # 2. Open by Name (Title)
            try:
                sh = client.open(spreadsheet_name)
            except gspread.SpreadsheetNotFound:
                print(f"Sheet '{spreadsheet_name}' not found. Creating it...")
                sh = client.create(spreadsheet_name)

            # 3. Select or Create Worksheet (Tab)
            try:
                worksheet = sh.worksheet(tab_name)
                worksheet.clear() # Clear old data
            except gspread.WorksheetNotFound:
                worksheet = sh.add_worksheet(title=tab_name, rows=len(data)+100, cols=20)

            # 4. Prepare Data
            headers = list(data[0].keys())
            rows = [[row.get(col, '') for col in headers] for row in data]
            all_values = [headers] + rows

            # 5. Update
            worksheet.update(all_values)
            print(f"Successfully uploaded {len(data)} rows to '{spreadsheet_name}' (Tab: {tab_name})")

        except Exception as e:
            print(f"Google Sheet Upload Failed: {e}")

    @staticmethod
    def to_bigquery(data, project_id, dataset_id, table_id):
        if not data:
            print("No data to upload.")
            return

        client = bigquery.Client(project=project_id)
        table_ref = f"{project_id}.{dataset_id}.{table_id}"
        
        print(f"Uploading {len(data)} rows to BigQuery table {table_ref}...")
        
        job_config = bigquery.LoadJobConfig(
            autodetect=True,
            source_format=bigquery.SourceFormat.NEWLINE_DELIMITED_JSON,
            write_disposition=bigquery.WriteDisposition.WRITE_APPEND
        )

        try:
            job = client.load_table_from_json(data, table_ref, job_config=job_config)
            job.result() 
            print(f"Upload successful. Loaded {job.output_rows} rows.")
        except Exception as e:
            print(f"BigQuery Upload Failed: {e}")
            if hasattr(e, 'errors'):
                print(e.errors)