# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
QuickBooks Online Accounting Skill

View invoices, expenses, profit/loss, and customers.

Setup:
    QUICKBOOKS_ACCESS_TOKEN=your_oauth_token
    QUICKBOOKS_REALM_ID=your_company_id

Get credentials at: https://developer.intuit.com/
API: https://quickbooks.api.intuit.com/v3/
"""

import logging

from familiar.core.api_cache import cached
from familiar.skills._api_utils import (
    APIError,
    api_get,
    get_env,
)

logger = logging.getLogger(__name__)


def _token() -> str:
    return get_env("QUICKBOOKS_ACCESS_TOKEN") or ""


def _realm_id() -> str:
    return get_env("QUICKBOOKS_REALM_ID") or ""


def _base_url() -> str:
    return f"https://quickbooks.api.intuit.com/v3/company/{_realm_id()}"


def _headers() -> dict:
    return {
        "Authorization": f"Bearer {_token()}",
        "Accept": "application/json",
    }


def _check_config() -> str:
    if not _token():
        return (
            "QuickBooks not configured.\n"
            "Set QUICKBOOKS_ACCESS_TOKEN and QUICKBOOKS_REALM_ID.\n"
            "Get credentials at: https://developer.intuit.com/"
        )
    if not _realm_id():
        return "QUICKBOOKS_REALM_ID not set."
    return ""


# ---------------------------------------------------------------------------
# Tool handlers
# ---------------------------------------------------------------------------


def qb_invoices(data: dict) -> str:
    """List recent QuickBooks invoices."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)

    try:
        query = f"SELECT * FROM Invoice ORDERBY MetaData.CreateTime DESC MAXRESULTS {limit}"
        result = _query_cached(query)

        response = result.get("QueryResponse", {})
        invoices = response.get("Invoice", [])

        if not invoices:
            return "No invoices found."

        lines = [f"**Invoices** (showing {len(invoices)}):", ""]

        for i, inv in enumerate(invoices, 1):
            doc_num = inv.get("DocNumber", "")
            total = inv.get("TotalAmt", 0)
            currency = inv.get("CurrencyRef", {}).get("value", "USD")
            balance = inv.get("Balance", 0)
            due_date = inv.get("DueDate", "")
            customer = inv.get("CustomerRef", {}).get("name", "")

            status = "Paid" if balance == 0 else f"Due: ${balance:.2f}"

            lines.append(f"{i}. **Invoice #{doc_num}** — ${total:.2f} {currency}")
            details = []
            if customer:
                details.append(customer)
            details.append(status)
            if due_date:
                details.append(f"Due: {due_date}")
            lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("QuickBooks invoices error: %s", e)
        return f"Error fetching invoices: {e}"


def qb_expenses(data: dict) -> str:
    """List recent expenses/purchases."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)

    try:
        query = f"SELECT * FROM Purchase ORDERBY MetaData.CreateTime DESC MAXRESULTS {limit}"
        result = _query_cached(query)

        response = result.get("QueryResponse", {})
        purchases = response.get("Purchase", [])

        if not purchases:
            return "No expenses found."

        lines = [f"**Expenses** (showing {len(purchases)}):", ""]

        for i, p in enumerate(purchases, 1):
            total = p.get("TotalAmt", 0)
            currency = p.get("CurrencyRef", {}).get("value", "USD")
            txn_date = p.get("TxnDate", "")
            payment_type = p.get("PaymentType", "")
            vendor = p.get("EntityRef", {}).get("name", "")

            lines.append(f"{i}. **${total:.2f} {currency}**")
            details = []
            if vendor:
                details.append(vendor)
            if txn_date:
                details.append(txn_date)
            if payment_type:
                details.append(payment_type)
            lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("QuickBooks expenses error: %s", e)
        return f"Error fetching expenses: {e}"


def qb_profit_loss(data: dict) -> str:
    """Get profit and loss report."""
    err = _check_config()
    if err:
        return err

    start_date = data.get("start_date", "")
    end_date = data.get("end_date", "")

    try:
        params = {}
        if start_date:
            params["start_date"] = start_date
        if end_date:
            params["end_date"] = end_date

        result = _report_cached("ProfitAndLoss", start_date, end_date)

        header = result.get("Header", {})
        report_name = header.get("ReportName", "Profit and Loss")
        start = header.get("StartPeriod", "")
        end = header.get("EndPeriod", "")

        rows = result.get("Rows", {}).get("Row", [])

        lines = [
            f"**{report_name}**",
            f"Period: {start} to {end}",
            "",
        ]

        for row in rows:
            header_data = row.get("Header", {})
            row_type = row.get("type", "")
            summary = row.get("Summary", {})

            if row_type == "Section":
                section_name = header_data.get("ColData", [{}])[0].get("value", "")
                if section_name:
                    lines.append(f"**{section_name}**")

                # Section rows
                sub_rows = row.get("Rows", {}).get("Row", [])
                for sr in sub_rows[:10]:
                    col_data = sr.get("ColData", [])
                    if len(col_data) >= 2:
                        name = col_data[0].get("value", "")
                        amount = col_data[1].get("value", "0")
                        if name and amount != "0":
                            lines.append(f"  {name}: ${float(amount):,.2f}")

                # Summary
                sum_cols = summary.get("ColData", [])
                if len(sum_cols) >= 2:
                    total_name = sum_cols[0].get("value", "")
                    total_amt = sum_cols[1].get("value", "0")
                    if total_name:
                        lines.append(f"  **{total_name}: ${float(total_amt):,.2f}**")
                lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("QuickBooks P&L error: %s", e)
        return f"Error fetching P&L report: {e}"


def qb_customers(data: dict) -> str:
    """List QuickBooks customers."""
    err = _check_config()
    if err:
        return err

    limit = min(int(data.get("limit", 20)), 100)

    try:
        query = f"SELECT * FROM Customer MAXRESULTS {limit}"
        result = _query_cached(query)

        response = result.get("QueryResponse", {})
        customers = response.get("Customer", [])

        if not customers:
            return "No customers found."

        lines = [f"**Customers** (showing {len(customers)}):", ""]

        for i, c in enumerate(customers, 1):
            name = c.get("DisplayName", c.get("CompanyName", ""))
            email = c.get("PrimaryEmailAddr", {}).get("Address", "")
            phone = c.get("PrimaryPhone", {}).get("FreeFormNumber", "")
            balance = c.get("Balance", 0)
            cid = c.get("Id", "")

            lines.append(f"{i}. **{name}** (ID: {cid})")
            details = []
            if email:
                details.append(email)
            if phone:
                details.append(phone)
            if balance:
                details.append(f"Balance: ${balance:.2f}")
            if details:
                lines.append(f"   {' | '.join(details)}")
            lines.append("")

        return "\n".join(lines)

    except APIError as e:
        return str(e)
    except Exception as e:
        logger.error("QuickBooks customers error: %s", e)
        return f"Error fetching customers: {e}"


@cached(prefix="qb_query", ttl=120)
def _query_cached(query: str) -> dict:
    return api_get(
        f"{_base_url()}/query",
        params={"query": query},
        headers=_headers(),
        service_name="QuickBooks",
    )


@cached(prefix="qb_report", ttl=300)
def _report_cached(report_name: str, start_date: str, end_date: str) -> dict:
    params = {}
    if start_date:
        params["start_date"] = start_date
    if end_date:
        params["end_date"] = end_date
    return api_get(
        f"{_base_url()}/reports/{report_name}",
        params=params,
        headers=_headers(),
        service_name="QuickBooks",
    )


# ---------------------------------------------------------------------------
# Tool definitions
# ---------------------------------------------------------------------------

TOOLS = [
    {
        "name": "qb_invoices",
        "description": "List recent QuickBooks invoices with amounts, customers, and due dates.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": qb_invoices,
        "category": "quickbooks",
    },
    {
        "name": "qb_expenses",
        "description": "List recent expenses and purchases with vendors and dates.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": qb_expenses,
        "category": "quickbooks",
    },
    {
        "name": "qb_profit_loss",
        "description": "Get QuickBooks Profit and Loss report with income, expenses, and net.",
        "input_schema": {
            "type": "object",
            "properties": {
                "start_date": {"type": "string", "description": "Start date (YYYY-MM-DD)"},
                "end_date": {"type": "string", "description": "End date (YYYY-MM-DD)"},
            },
        },
        "handler": qb_profit_loss,
        "category": "quickbooks",
    },
    {
        "name": "qb_customers",
        "description": "List QuickBooks customers with contact info and balances.",
        "input_schema": {
            "type": "object",
            "properties": {
                "limit": {
                    "type": "integer",
                    "description": "Max results (1-100, default 20)",
                    "default": 20,
                },
            },
        },
        "handler": qb_customers,
        "category": "quickbooks",
    },
]
