"""Tax reporting and 1099 form generation."""

import io
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from typing import Dict, Any, List, Optional
from datetime import datetime, timedelta
from google.cloud import firestore
from reportlab.lib.pagesizes import letter
from reportlab.lib.units import inch
from reportlab.pdfgen import canvas
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import Paragraph, Spacer, Table, TableStyle
from agenticlypay.stripe_client import StripeClient
from agenticlypay.payouts import PayoutManager
from agenticlypay.utils.firestore_storage import FirestoreStorage
from agenticlypay.config import config
import os

db = firestore.Client(project=config.project_id or "agenticlypay-com")
storage = FirestoreStorage()


class TaxReporter:
    """Handles tax reporting and 1099 form generation."""

    def __init__(self):
        """Initialize the tax reporter."""
        self.stripe_client = StripeClient()
        self.payout_manager = PayoutManager()
        self.storage = FirestoreStorage()

    def _get_email_from_account_id(self, developer_account_id: str) -> Optional[str]:
        """Retrieve developer email from account_id."""
        # Try account_email_mapping first
        mapping_doc = db.collection("account_email_mapping").document(developer_account_id).get()
        if mapping_doc.exists:
            return mapping_doc.to_dict().get("email")
        
        # Try square_payouts collection
        payouts_query = (
            db.collection("square_payouts")
            .where("developer_account_id", "==", developer_account_id)
            .limit(1)
            .stream()
        )
        for doc in payouts_query:
            data = doc.to_dict()
            if data and "email" in data:
                return data["email"]
        
        return None

    def calculate_annual_earnings(
        self, developer_account_id: str, year: int
    ) -> Dict[str, Any]:
        """
        Calculate total annual earnings for a developer from Square payouts.

        Args:
            developer_account_id: Connected account ID
            year: Year (e.g., 2024)

        Returns:
            Dictionary with annual earnings breakdown
        """
        # Calculate date range for the year
        start_date = datetime(year, 1, 1)
        end_date = datetime(year + 1, 1, 1)
        
        # Query Square payouts for this account and year
        payouts_query = (
            db.collection("square_payouts")
            .where("developer_account_id", "==", developer_account_id)
            .where("year", "==", year)
            .stream()
        )

        total_amount = 0
        total_transactions = 0
        monthly_breakdown = {}
        email = None

        for doc in payouts_query:
            data = doc.to_dict()
            if data:
                if not email and "email" in data:
                    email = data["email"]
                
                amount = data.get("amount", 0)
                month = data.get("month", 0)
                
                if month not in monthly_breakdown:
                    monthly_breakdown[month] = {
                        "total_amount": 0,
                        "transaction_count": 0,
                        "net_amount": 0,
                    }
                
                monthly_breakdown[month]["total_amount"] += amount
                monthly_breakdown[month]["transaction_count"] += data.get("transaction_count", 0)
                monthly_breakdown[month]["net_amount"] += amount
                
                total_amount += amount
                total_transactions += data.get("transaction_count", 0)

        # Convert monthly breakdown to list format
        monthly_list = []
        for month in range(1, 13):
            if month in monthly_breakdown:
                monthly_list.append({
                    "year": year,
                    "month": month,
                    "total_amount": monthly_breakdown[month]["total_amount"],
                    "total_fees": 0,  # Fees already deducted before Square payout
                    "net_amount": monthly_breakdown[month]["net_amount"],
                    "transaction_count": monthly_breakdown[month]["transaction_count"],
                    "currency": "usd",
                })
            else:
                monthly_list.append({
                    "year": year,
                    "month": month,
                    "total_amount": 0,
                    "total_fees": 0,
                    "net_amount": 0,
                    "transaction_count": 0,
                    "currency": "usd",
                })

        # For Square payouts, net_amount equals total_amount (fees already deducted)
        net_amount = total_amount
        total_fees = 0  # Fees were deducted before payout

        return {
            "developer_account_id": developer_account_id,
            "email": email,
            "year": year,
            "total_amount": total_amount,
            "total_fees": total_fees,
            "net_amount": net_amount,
            "total_transactions": total_transactions,
            "monthly_breakdown": monthly_list,
            "currency": "usd",
        }

    def generate_1099_pdf(
        self, email: str, developer_account_id: str, year: int, amount_cents: int
    ) -> bytes:
        """
        Generate a 1099-MISC PDF form.

        Args:
            email: Developer email address
            developer_account_id: Connected account ID
            year: Tax year
            amount_cents: Amount in cents

        Returns:
            PDF bytes
        """
        buffer = io.BytesIO()
        c = canvas.Canvas(buffer, pagesize=letter)
        width, height = letter

        # Get tax information
        tax_info = storage.get_tax_info(email) or {}
        recipient_name = tax_info.get("name", email)
        recipient_tin = tax_info.get("ssn") or tax_info.get("ein", "")
        recipient_address = tax_info.get("address", {})

        # Payer information from config
        payer_name = config.payer_name
        payer_tin = config.payer_tin or ""
        payer_address = {
            "street": config.payer_address_street or "",
            "city": config.payer_address_city or "",
            "state": config.payer_address_state or "",
            "zip": config.payer_address_zip or "",
        }

        # Convert amount from cents to dollars
        amount_dollars = amount_cents / 100.0

        # Form title
        c.setFont("Helvetica-Bold", 16)
        c.drawString(72, height - 72, "Form 1099-MISC")
        c.setFont("Helvetica", 10)
        c.drawString(72, height - 90, f"Tax Year {year}")

        # Payer information (top left)
        y_pos = height - 120
        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "PAYER'S name, street address, city, state, ZIP code, and telephone no.")
        y_pos -= 15
        c.setFont("Helvetica", 9)
        c.drawString(72, y_pos, payer_name)
        y_pos -= 12
        if payer_address["street"]:
            c.drawString(72, y_pos, payer_address["street"])
            y_pos -= 12
        city_state_zip = f"{payer_address['city']}, {payer_address['state']} {payer_address['zip']}".strip()
        if city_state_zip:
            c.drawString(72, y_pos, city_state_zip)
            y_pos -= 12
        if config.payer_phone:
            c.drawString(72, y_pos, config.payer_phone)
            y_pos -= 20

        # Payer TIN
        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "PAYER'S TIN")
        y_pos -= 15
        c.setFont("Helvetica", 9)
        c.drawString(72, y_pos, payer_tin)
        y_pos -= 30

        # Recipient information
        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "RECIPIENT'S name")
        y_pos -= 15
        c.setFont("Helvetica", 9)
        c.drawString(72, y_pos, recipient_name)
        y_pos -= 20

        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "Street address (including apt. no.)")
        y_pos -= 15
        c.setFont("Helvetica", 9)
        if isinstance(recipient_address, dict):
            c.drawString(72, y_pos, recipient_address.get("street", ""))
            y_pos -= 12
            city_state_zip = f"{recipient_address.get('city', '')}, {recipient_address.get('state', '')} {recipient_address.get('zip', '')}".strip()
            if city_state_zip:
                c.drawString(72, y_pos, city_state_zip)
                y_pos -= 20
        else:
            c.drawString(72, y_pos, str(recipient_address))
            y_pos -= 20

        # Recipient TIN
        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "RECIPIENT'S TIN")
        y_pos -= 15
        c.setFont("Helvetica", 9)
        c.drawString(72, y_pos, recipient_tin)
        y_pos -= 30

        # Box 1: Nonemployee compensation
        c.setFont("Helvetica-Bold", 10)
        c.drawString(72, y_pos, "1 Nonemployee compensation")
        y_pos -= 15
        c.setFont("Helvetica", 12)
        amount_str = f"${amount_dollars:,.2f}"
        c.drawString(72, y_pos, amount_str)
        y_pos -= 30

        # Footer
        c.setFont("Helvetica", 8)
        c.drawString(72, 72, "Copy B - For Recipient")
        c.drawString(72, 60, "This is important tax information and is being furnished to the Internal Revenue Service.")

        c.save()
        buffer.seek(0)
        return buffer.getvalue()

    def send_1099_email(
        self, email: str, developer_account_id: str, year: int, amount_cents: int
    ) -> Dict[str, Any]:
        """
        Send 1099 form via email with PDF attachment.

        Args:
            email: Recipient email address
            developer_account_id: Connected account ID
            year: Tax year
            amount_cents: Amount in cents

        Returns:
            Dictionary with delivery status
        """
        # Check consent
        consent = storage.get_1099_consent(email)
        if not consent or not consent.get("consented", False):
            return {
                "success": False,
                "error": "Electronic delivery consent not provided",
                "message": "Recipient must consent to electronic delivery of 1099 forms",
            }

        # Generate PDF
        try:
            pdf_bytes = self.generate_1099_pdf(email, developer_account_id, year, amount_cents)
        except Exception as e:
            return {
                "success": False,
                "error": f"Failed to generate PDF: {str(e)}",
            }

        # Store form record
        form_id = f"{developer_account_id}_{year}"
        form_ref = db.collection("1099_forms").document(form_id)
        form_ref.set({
            "form_id": form_id,
            "email": email,
            "developer_account_id": developer_account_id,
            "year": year,
            "amount_cents": amount_cents,
            "generated_at": firestore.SERVER_TIMESTAMP,
            "sent_at": None,
        })

        # Send email
        try:
            smtp_host = os.getenv("SMTP_HOST", "smtp.gmail.com")
            smtp_port = int(os.getenv("SMTP_PORT", "587"))
            smtp_user = os.getenv("SMTP_USER", "")
            smtp_password = os.getenv("SMTP_PASSWORD", "")
            smtp_from = os.getenv("SMTP_FROM", "noreply@agenticlypay.com")

            msg = MIMEMultipart()
            msg["From"] = smtp_from
            msg["To"] = email
            msg["Subject"] = f"Your {year} Form 1099-MISC from {config.payer_name}"

            # Email body with IRS disclosures
            body = f"""Dear Developer,

Please find attached your Form 1099-MISC for tax year {year}.

IMPORTANT IRS DISCLOSURES:

1. Right to Paper Copy: You have the right to receive a paper copy of this form. 
   To request a paper copy, please contact us at {smtp_from} or visit our developer console.

2. Withdrawal of Consent: You may withdraw your consent to receive electronic 
   forms at any time by contacting us or using the developer console.

3. Hardware/Software Requirements: To access this form, you need:
   - A device capable of viewing PDF files
   - PDF reader software (Adobe Reader, etc.)
   - Internet connection to download the attachment

4. Access Period: This form will remain accessible until October 15, {year + 1}.

5. Retention: Please retain this form for your tax records.

If you have any questions, please contact us at {smtp_from}.

Best regards,
{config.payer_name}
"""
            msg.attach(MIMEText(body, "plain"))

            # Attach PDF
            attachment = MIMEBase("application", "pdf")
            attachment.set_payload(pdf_bytes)
            encoders.encode_base64(attachment)
            attachment.add_header(
                "Content-Disposition",
                f'attachment; filename="1099-MISC-{year}-{developer_account_id}.pdf"',
            )
            msg.attach(attachment)

            # Send email
            server = smtplib.SMTP(smtp_host, smtp_port)
            server.starttls()
            server.login(smtp_user, smtp_password)
            server.send_message(msg)
            server.quit()

            # Update form record
            form_ref.update({
                "sent_at": firestore.SERVER_TIMESTAMP,
                "delivery_status": "sent",
            })

            return {
                "success": True,
                "form_id": form_id,
                "email": email,
                "sent_at": datetime.now().isoformat(),
            }
        except Exception as e:
            form_ref.update({
                "delivery_status": "failed",
                "error": str(e),
            })
            return {
                "success": False,
                "error": f"Failed to send email: {str(e)}",
            }

    def generate_and_send_1099(
        self, developer_account_id: str, year: int
    ) -> Dict[str, Any]:
        """
        Generate and send 1099 form via email.

        Args:
            developer_account_id: Connected account ID
            year: Tax year

        Returns:
            Dictionary with generation and delivery status
        """
        # Calculate annual earnings
        annual_earnings = self.calculate_annual_earnings(developer_account_id, year)

        # IRS threshold for 1099-MISC is $600
        if annual_earnings["net_amount"] < 60000:  # $600 in cents
            return {
                "success": False,
                "message": "Earnings below $600 threshold, 1099 not required",
                "earnings": annual_earnings,
            }

        email = annual_earnings.get("email")
        if not email:
            email = self._get_email_from_account_id(developer_account_id)
            if not email:
                return {
                    "success": False,
                    "error": "Email address not found for developer account",
                }

        # Send 1099 via email
        result = self.send_1099_email(
            email, developer_account_id, year, annual_earnings["net_amount"]
        )

        if result["success"]:
            return {
                "success": True,
                "form_id": result["form_id"],
                "email": email,
                "year": year,
                "amount": annual_earnings["net_amount"],
                "earnings": annual_earnings,
                "sent_at": result["sent_at"],
            }
        else:
            return {
                "success": False,
                "error": result.get("error", "Unknown error"),
                "earnings": annual_earnings,
            }

    def generate_1099_form(
        self, developer_account_id: str, year: int
    ) -> Dict[str, Any]:
        """
        Generate a 1099 form for a developer (legacy method, now uses email delivery).

        Args:
            developer_account_id: Connected account ID
            year: Tax year (e.g., 2024)

        Returns:
            Dictionary with 1099 form information
        """
        return self.generate_and_send_1099(developer_account_id, year)

    def generate_all_1099_forms(
        self, year: int, developer_account_ids: Optional[List[str]] = None
    ) -> Dict[str, Any]:
        """
        Generate and send 1099 forms for all eligible developers with Square payouts.

        Args:
            year: Tax year (e.g., 2024)
            developer_account_ids: List of account IDs (None for all)

        Returns:
            Dictionary with generation results
        """
        results = {
            "year": year,
            "generated": [],
            "failed": [],
            "skipped": [],
            "no_consent": [],
        }

        # If no account IDs provided, query all developers with Square payouts for the year
        if not developer_account_ids:
            # Query all unique developer_account_ids from square_payouts for this year
            payouts_query = (
                db.collection("square_payouts")
                .where("year", "==", year)
                .stream()
            )
            
            account_ids_set = set()
            for doc in payouts_query:
                data = doc.to_dict()
                if data and "developer_account_id" in data:
                    account_ids_set.add(data["developer_account_id"])
            
            developer_account_ids = list(account_ids_set)

        if not developer_account_ids:
            return {
                "error": "No developers found with payouts for this year",
                "results": results,
            }

        for account_id in developer_account_ids:
            try:
                # Calculate earnings to check threshold
                annual_earnings = self.calculate_annual_earnings(account_id, year)
                
                if annual_earnings["net_amount"] < 60000:  # $600 threshold
                    results["skipped"].append({
                        "account_id": account_id,
                        "email": annual_earnings.get("email"),
                        "reason": "Earnings below $600 threshold",
                    })
                    continue

                email = annual_earnings.get("email") or self._get_email_from_account_id(account_id)
                if not email:
                    results["failed"].append({
                        "account_id": account_id,
                        "error": "Email address not found",
                    })
                    continue

                # Check consent
                consent = storage.get_1099_consent(email)
                if not consent or not consent.get("consented", False):
                    results["no_consent"].append({
                        "account_id": account_id,
                        "email": email,
                        "reason": "Electronic delivery consent not provided",
                    })
                    continue

                # Generate and send
                form_result = self.generate_and_send_1099(account_id, year)
                if form_result["success"]:
                    results["generated"].append(form_result)
                else:
                    results["failed"].append({
                        "account_id": account_id,
                        "email": email,
                        "error": form_result.get("error", "Unknown error"),
                    })
            except Exception as e:
                results["failed"].append({
                    "account_id": account_id,
                    "error": str(e),
                })

        return results

    def get_tax_forms(
        self, developer_account_id: str, year: Optional[int] = None
    ) -> List[Dict[str, Any]]:
        """
        Get tax forms for a developer.

        Args:
            developer_account_id: Connected account ID
            year: Tax year (optional, defaults to current year)

        Returns:
            List of tax form dictionaries
        """
        if not year:
            year = datetime.now().year

        # Calculate annual earnings
        annual_earnings = self.calculate_annual_earnings(developer_account_id, year)

        # Try to retrieve tax form
        # Note: Stripe Tax API may have different methods for retrieving forms
        # This is a placeholder implementation
        return [
            {
                "year": year,
                "developer_account_id": developer_account_id,
                "amount": annual_earnings["net_amount"],
                "earnings": annual_earnings,
            }
        ]

