from datetime import datetime, date
from decimal import Decimal
from io import BytesIO
from typing import List
from uuid import UUID
import logging

from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.units import inch
from sqlalchemy import select, and_
from sqlalchemy.ext.asyncio import AsyncSession

from ..models import Account
from ..models import UsageEvent

log = logging.getLogger(__name__)


class InvoiceGenerator:
    """Generates PDF invoices for billing"""

    def __init__(self, db: AsyncSession):
        self.db = db
        self.styles = getSampleStyleSheet()
        self.price_per_credit = Decimal("0.01")  # $0.01 per credit

    async def generate_monthly_invoice(
        self, account_id: UUID, year: int, month: int
    ) -> BytesIO:
        """Generate PDF invoice for a specific month"""

        # Get account details
        account = await self.db.get(Account, account_id)
        if not account:
            raise ValueError(f"Account {account_id} not found")

        # Get usage events for the month
        start_date = datetime(year, month, 1)
        if month == 12:
            end_date = datetime(year + 1, 1, 1)
        else:
            end_date = datetime(year, month + 1, 1)

        stmt = (
            select(UsageEvent)
            .where(
                and_(
                    UsageEvent.account_id == account_id,
                    UsageEvent.time >= start_date,
                    UsageEvent.time < end_date,
                    UsageEvent.credits_consumed > 0,  # Only billable events
                )
            )
            .order_by(UsageEvent.time)
        )

        result = await self.db.execute(stmt)
        events = result.scalars().all()

        # Calculate totals
        total_credits = sum(event.credits_consumed for event in events)
        total_amount = total_credits * self.price_per_credit

        # Generate invoice
        return self._create_pdf(
            account=account,
            events=events,
            year=year,
            month=month,
            total_credits=total_credits,
            total_amount=total_amount,
        )

    def _create_pdf(
        self,
        account: Account,
        events: List[UsageEvent],
        year: int,
        month: int,
        total_credits: int,
        total_amount: Decimal,
    ) -> BytesIO:
        """Create the actual PDF document"""

        buffer = BytesIO()
        doc = SimpleDocTemplate(buffer, pagesize=letter)
        story = []

        # Header
        invoice_num = f"INV-{year}{month:02d}-{str(account.id)[:8]}"
        invoice_date = date(year, month, 1).strftime("%B %Y")

        header_style = ParagraphStyle(
            "CustomHeader",
            parent=self.styles["Heading1"],
            fontSize=24,
            textColor=colors.HexColor("#1a1a1a"),
        )

        story.append(Paragraph("FoundryMatch", header_style))
        story.append(Spacer(1, 0.2 * inch))

        # Invoice details
        story.append(
            Paragraph(f"<b>Invoice Number:</b> {invoice_num}", self.styles["Normal"])
        )
        story.append(
            Paragraph(f"<b>Invoice Period:</b> {invoice_date}", self.styles["Normal"])
        )
        story.append(
            Paragraph(f"<b>Account:</b> {account.name}", self.styles["Normal"])
        )
        story.append(
            Paragraph(f"<b>Account ID:</b> {str(account.id)}", self.styles["Normal"])
        )
        story.append(Spacer(1, 0.5 * inch))

        # Usage summary table
        summary_data = [
            ["Description", "Quantity", "Unit Price", "Amount"],
            [
                f"API Credits - {invoice_date}",
                f"{total_credits:,}",
                "$0.01",
                f"${total_amount:.2f}",
            ],
        ]

        summary_table = Table(
            summary_data, colWidths=[3.5 * inch, 1.5 * inch, 1 * inch, 1 * inch]
        )
        summary_table.setStyle(
            TableStyle(
                [
                    ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
                    ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
                    ("ALIGN", (0, 0), (-1, -1), "CENTER"),
                    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
                    ("FONTSIZE", (0, 0), (-1, 0), 12),
                    ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
                    ("GRID", (0, 0), (-1, -1), 1, colors.black),
                ]
            )
        )

        story.append(summary_table)
        story.append(Spacer(1, 0.5 * inch))

        # Total
        story.append(
            Paragraph(f"<b>Total Due: ${total_amount:.2f}</b>", self.styles["Heading2"])
        )
        story.append(Spacer(1, 0.5 * inch))

        # Usage details (summarized by event type)
        story.append(Paragraph("Usage Details by Type", self.styles["Heading3"]))
        story.append(Spacer(1, 0.2 * inch))

        # Group events by type
        event_summary = {}
        for event in events:
            if event.event_type not in event_summary:
                event_summary[event.event_type] = {"count": 0, "credits": 0}
            event_summary[event.event_type]["count"] += 1
            event_summary[event.event_type]["credits"] += event.credits_consumed

        detail_data = [["Event Type", "Count", "Credits Used"]]
        for event_type, data in event_summary.items():
            detail_data.append(
                [
                    event_type.replace("_", " ").title(),
                    f"{data['count']:,}",
                    f"{data['credits']:,}",
                ]
            )

        detail_table = Table(detail_data, colWidths=[3 * inch, 2 * inch, 2 * inch])
        detail_table.setStyle(
            TableStyle(
                [
                    ("BACKGROUND", (0, 0), (-1, 0), colors.lightgrey),
                    ("ALIGN", (0, 0), (-1, -1), "CENTER"),
                    ("FONTNAME", (0, 0), (-1, 0), "Helvetica-Bold"),
                    ("GRID", (0, 0), (-1, -1), 0.5, colors.grey),
                ]
            )
        )

        story.append(detail_table)

        # Build PDF
        doc.build(story)
        buffer.seek(0)

        return buffer

    async def get_invoice_list(self, account_id: UUID, limit: int = 12) -> List[dict]:
        """Get list of available invoices"""

        query = """
        SELECT
            DATE_TRUNC('month', time) as month,
            SUM(credits_consumed) as total_credits,
            COUNT(*) as event_count
        FROM usage_events
        WHERE account_id = :account_id
            AND credits_consumed > 0
        GROUP BY DATE_TRUNC('month', time)
        ORDER BY month DESC
        LIMIT :limit
        """

        result = await self.db.execute(
            query, {"account_id": account_id, "limit": limit}
        )

        invoices = []
        for row in result:
            month_date = row.month
            total_amount = row.total_credits * float(self.price_per_credit)

            invoices.append(
                {
                    "invoice_id": f"INV-{month_date.year}{month_date.month:02d}-{str(account_id)[:8]}",
                    "year": month_date.year,
                    "month": month_date.month,
                    "period": month_date.strftime("%B %Y"),
                    "total_credits": row.total_credits,
                    "total_amount": f"${total_amount:.2f}",
                    "event_count": row.event_count,
                }
            )

        return invoices
