"""
QuickBooks integration connector.
Sync invoices, expenses, and payments with QuickBooks Online.
"""

import base64
import logging
import os
from datetime import datetime, timedelta
from typing import Any, Dict, List, Optional

import requests

from app.integrations.base import BaseConnector

logger = logging.getLogger(__name__)


class QuickBooksConnector(BaseConnector):
    """QuickBooks Online integration connector."""

    display_name = "QuickBooks Online"
    description = "Sync invoices, expenses, and payments with QuickBooks"
    icon = "quickbooks"

    BASE_URL = "https://sandbox-quickbooks.api.intuit.com"  # Sandbox
    PRODUCTION_URL = "https://quickbooks.api.intuit.com"  # Production

    @property
    def provider_name(self) -> str:
        return "quickbooks"

    def get_base_url(self):
        """Get base URL based on environment"""
        use_sandbox = self.integration.config.get("use_sandbox", True) if self.integration else True
        return self.BASE_URL if use_sandbox else self.PRODUCTION_URL

    def get_authorization_url(self, redirect_uri: str, state: str = None) -> str:
        """Get QuickBooks OAuth authorization URL."""
        from app.models import Settings

        settings = Settings.get_settings()
        creds = settings.get_integration_credentials("quickbooks")
        client_id = creds.get("client_id") or os.getenv("QUICKBOOKS_CLIENT_ID")
        client_secret = creds.get("client_secret") or os.getenv("QUICKBOOKS_CLIENT_SECRET")

        if not client_id:
            raise ValueError("QUICKBOOKS_CLIENT_ID not configured")

        auth_url = "https://appcenter.intuit.com/connect/oauth2"

        scopes = ["com.intuit.quickbooks.accounting", "com.intuit.quickbooks.payment"]

        params = {
            "client_id": client_id,
            "scope": " ".join(scopes),
            "redirect_uri": redirect_uri,
            "response_type": "code",
            "access_type": "offline",
            "state": state or "",
        }

        query_string = "&".join([f"{k}={v}" for k, v in params.items()])
        return f"{auth_url}?{query_string}"

    def exchange_code_for_tokens(self, code: str, redirect_uri: str) -> Dict[str, Any]:
        """Exchange authorization code for tokens."""
        from app.models import Settings

        settings = Settings.get_settings()
        creds = settings.get_integration_credentials("quickbooks")
        client_id = creds.get("client_id") or os.getenv("QUICKBOOKS_CLIENT_ID")
        client_secret = creds.get("client_secret") or os.getenv("QUICKBOOKS_CLIENT_SECRET")

        if not client_id or not client_secret:
            raise ValueError("QuickBooks OAuth credentials not configured")

        token_url = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"

        # QuickBooks requires Basic Auth for token exchange
        auth_string = f"{client_id}:{client_secret}"
        auth_bytes = auth_string.encode("ascii")
        auth_b64 = base64.b64encode(auth_bytes).decode("ascii")

        response = requests.post(
            token_url,
            headers={
                "Authorization": f"Basic {auth_b64}",
                "Accept": "application/json",
                "Content-Type": "application/x-www-form-urlencoded",
            },
            data={"grant_type": "authorization_code", "code": code, "redirect_uri": redirect_uri},
        )

        response.raise_for_status()
        data = response.json()

        expires_at = None
        if "expires_in" in data:
            expires_at = datetime.utcnow() + timedelta(seconds=data["expires_in"])

        # Get company info
        company_info = {}
        if "access_token" in data and "realmId" in data:
            try:
                realm_id = data["realmId"]
                company_response = self._api_request(
                    "GET", f"/v3/company/{realm_id}/companyinfo/{realm_id}", data.get("access_token"), realm_id
                )
                if company_response:
                    company_info = company_response.get("CompanyInfo", {})
            except Exception as e:
                logger.debug("QuickBooks company info fetch after OAuth failed (optional): %s", e)

        return {
            "access_token": data.get("access_token"),
            "refresh_token": data.get("refresh_token"),
            "expires_at": expires_at.isoformat() if expires_at else None,
            "token_type": "Bearer",
            "realm_id": data.get("realmId"),  # QuickBooks company ID
            "extra_data": {"company_name": company_info.get("CompanyName", ""), "company_id": data.get("realmId")},
        }

    def refresh_access_token(self) -> Dict[str, Any]:
        """Refresh access token using refresh token."""
        if not self.credentials or not self.credentials.refresh_token:
            raise ValueError("No refresh token available")

        from app.models import Settings

        settings = Settings.get_settings()
        creds = settings.get_integration_credentials("quickbooks")
        client_id = creds.get("client_id") or os.getenv("QUICKBOOKS_CLIENT_ID")
        client_secret = creds.get("client_secret") or os.getenv("QUICKBOOKS_CLIENT_SECRET")

        token_url = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer"

        auth_string = f"{client_id}:{client_secret}"
        auth_bytes = auth_string.encode("ascii")
        auth_b64 = base64.b64encode(auth_bytes).decode("ascii")

        response = requests.post(
            token_url,
            headers={
                "Authorization": f"Basic {auth_b64}",
                "Accept": "application/json",
                "Content-Type": "application/x-www-form-urlencoded",
            },
            data={"grant_type": "refresh_token", "refresh_token": self.credentials.refresh_token},
        )

        response.raise_for_status()
        data = response.json()

        expires_at = None
        if "expires_in" in data:
            expires_at = datetime.utcnow() + timedelta(seconds=data["expires_in"])

        # Update credentials
        self.credentials.access_token = data.get("access_token")
        if "refresh_token" in data:
            self.credentials.refresh_token = data.get("refresh_token")
        if expires_at:
            self.credentials.expires_at = expires_at
        self.credentials.save()

        return {"access_token": data.get("access_token"), "expires_at": expires_at.isoformat() if expires_at else None}

    def test_connection(self) -> Dict[str, Any]:
        """Test connection to QuickBooks."""
        try:
            realm_id = self.integration.config.get("realm_id") if self.integration else None
            if not realm_id:
                return {"success": False, "message": "QuickBooks company not configured"}

            company_info = self._api_request(
                "GET", f"/v3/company/{realm_id}/companyinfo/{realm_id}", self.get_access_token(), realm_id
            )

            if company_info:
                company_name = company_info.get("CompanyInfo", {}).get("CompanyName", "Unknown")
                return {"success": True, "message": f"Connected to QuickBooks company: {company_name}"}
            else:
                return {"success": False, "message": "Failed to retrieve company information"}
        except Exception as e:
            return {"success": False, "message": f"Connection test failed: {str(e)}"}

    def _api_request(
        self, method: str, endpoint: str, access_token: str, realm_id: str, json_data: Optional[Dict] = None
    ) -> Optional[Dict]:
        """Make API request to QuickBooks"""
        base_url = self.get_base_url()
        url = f"{base_url}{endpoint}"

        headers = {
            "Authorization": f"Bearer {access_token}",
            "Accept": "application/json",
            "Content-Type": "application/json",
        }

        if realm_id:
            headers["realmId"] = realm_id

        try:
            if method.upper() == "GET":
                response = requests.get(url, headers=headers, timeout=30)
            elif method.upper() == "POST":
                response = requests.post(url, headers=headers, timeout=30, json=json_data or {})
            elif method.upper() == "PUT":
                response = requests.put(url, headers=headers, timeout=30, json=json_data or {})
            else:
                response = requests.request(method, url, headers=headers, timeout=30, json=json_data)

            response.raise_for_status()
            return response.json()
        except requests.exceptions.Timeout:
            logger.error(f"QuickBooks API request timeout: {method} {endpoint}")
            raise ValueError("QuickBooks API request timed out. Please try again.")
        except requests.exceptions.ConnectionError as e:
            logger.error(f"QuickBooks API connection error: {e}")
            raise ValueError(f"Failed to connect to QuickBooks API: {str(e)}")
        except requests.exceptions.HTTPError as e:
            error_detail = ""
            if e.response:
                try:
                    error_data = e.response.json()
                    error_detail = error_data.get("fault", {}).get("error", [{}])[0].get("detail", "")
                    if not error_detail:
                        error_detail = error_data.get("fault", {}).get("error", [{}])[0].get("message", "")
                except Exception:
                    error_detail = e.response.text[:200] if e.response.text else ""

            error_msg = f"QuickBooks API error ({e.response.status_code}): {error_detail or str(e)}"
            logger.error(f"QuickBooks API request failed: {error_msg}")
            raise ValueError(error_msg)
        except Exception as e:
            logger.error(f"QuickBooks API request failed: {e}", exc_info=True)
            raise ValueError(f"QuickBooks API request failed: {str(e)}")

    def sync_data(self, sync_type: str = "full") -> Dict[str, Any]:
        """Sync invoices and expenses with QuickBooks"""
        from app import db
        from app.models import Expense, Invoice

        try:
            realm_id = self.integration.config.get("realm_id")
            if not realm_id:
                return {"success": False, "message": "QuickBooks company not configured"}

            access_token = self.get_access_token()
            if not access_token:
                return {"success": False, "message": "No access token available. Please reconnect the integration."}

            synced_count = 0
            errors = []

            # Sync invoices (create as invoices in QuickBooks)
            if sync_type == "full" or sync_type == "invoices":
                try:
                    invoices = Invoice.query.filter(
                        Invoice.status.in_(["sent", "paid"]),
                        Invoice.created_at >= datetime.utcnow() - timedelta(days=90),
                    ).all()

                    for invoice in invoices:
                        try:
                            # Skip if already synced (has QuickBooks ID)
                            if (
                                hasattr(invoice, "metadata")
                                and invoice.metadata
                                and invoice.metadata.get("quickbooks_id")
                            ):
                                continue

                            qb_invoice = self._create_quickbooks_invoice(invoice, access_token, realm_id)
                            if qb_invoice:
                                # Store QuickBooks ID in invoice metadata
                                if not hasattr(invoice, "metadata") or not invoice.metadata:
                                    invoice.metadata = {}
                                invoice.metadata["quickbooks_id"] = qb_invoice.get("Id")
                                synced_count += 1
                        except ValueError as e:
                            # Validation errors - log but continue
                            error_msg = f"Invoice {invoice.id}: {str(e)}"
                            errors.append(error_msg)
                            logger.warning(error_msg)
                        except requests.exceptions.HTTPError as e:
                            # API errors - log with details
                            error_msg = f"Invoice {invoice.id}: QuickBooks API error - {e.response.status_code}: {e.response.text[:200] if e.response else str(e)}"
                            errors.append(error_msg)
                            logger.error(error_msg, exc_info=True)
                        except Exception as e:
                            # Other errors
                            error_msg = f"Invoice {invoice.id}: {str(e)}"
                            errors.append(error_msg)
                            logger.error(error_msg, exc_info=True)
                except Exception as e:
                    error_msg = f"Error fetching invoices: {str(e)}"
                    errors.append(error_msg)
                    logger.error(error_msg, exc_info=True)

            # Sync expenses (create as expenses in QuickBooks)
            if sync_type == "full" or sync_type == "expenses":
                try:
                    expenses = Expense.query.filter(
                        Expense.expense_date >= datetime.utcnow().date() - timedelta(days=90)
                    ).all()

                    for expense in expenses:
                        try:
                            # Skip if already synced
                            if (
                                hasattr(expense, "metadata")
                                and expense.metadata
                                and expense.metadata.get("quickbooks_id")
                            ):
                                continue

                            qb_expense = self._create_quickbooks_expense(expense, access_token, realm_id)
                            if qb_expense:
                                if not hasattr(expense, "metadata") or not expense.metadata:
                                    expense.metadata = {}
                                expense.metadata["quickbooks_id"] = qb_expense.get("Id")
                                synced_count += 1
                        except ValueError as e:
                            # Validation errors
                            error_msg = f"Expense {expense.id}: {str(e)}"
                            errors.append(error_msg)
                            logger.warning(error_msg)
                        except requests.exceptions.HTTPError as e:
                            # API errors
                            error_msg = f"Expense {expense.id}: QuickBooks API error - {e.response.status_code}: {e.response.text[:200] if e.response else str(e)}"
                            errors.append(error_msg)
                            logger.error(error_msg, exc_info=True)
                        except Exception as e:
                            # Other errors
                            error_msg = f"Expense {expense.id}: {str(e)}"
                            errors.append(error_msg)
                            logger.error(error_msg, exc_info=True)
                except Exception as e:
                    error_msg = f"Error fetching expenses: {str(e)}"
                    errors.append(error_msg)
                    logger.error(error_msg, exc_info=True)

            try:
                db.session.commit()
            except Exception as e:
                db.session.rollback()
                error_msg = f"Database error during sync: {str(e)}"
                errors.append(error_msg)
                logger.error(error_msg, exc_info=True)
                return {"success": False, "message": error_msg, "synced_count": synced_count, "errors": errors}

            if errors:
                return {
                    "success": True,
                    "synced_count": synced_count,
                    "errors": errors,
                    "message": f"Sync completed with {len(errors)} error(s). Synced {synced_count} items.",
                }

            return {
                "success": True,
                "synced_count": synced_count,
                "errors": errors,
                "message": f"Successfully synced {synced_count} items.",
            }

        except requests.exceptions.RequestException as e:
            error_msg = f"Network error during QuickBooks sync: {str(e)}"
            logger.error(error_msg, exc_info=True)
            return {"success": False, "message": error_msg}
        except Exception as e:
            error_msg = f"Sync failed: {str(e)}"
            logger.error(error_msg, exc_info=True)
            return {"success": False, "message": error_msg}

    def _create_quickbooks_invoice(self, invoice, access_token: str, realm_id: str) -> Optional[Dict]:
        """Create invoice in QuickBooks"""
        # Get customer mapping from integration config or invoice metadata
        customer_mapping = self.integration.config.get("customer_mappings", {}) if self.integration else {}
        item_mapping = self.integration.config.get("item_mappings", {}) if self.integration else {}

        # Try to get QuickBooks customer ID from mapping or metadata
        customer_qb_id = None
        if invoice.client_id:
            # Check mapping first
            customer_qb_id = customer_mapping.get(str(invoice.client_id))
            # Fallback to invoice metadata
            if not customer_qb_id and hasattr(invoice, "metadata") and invoice.metadata:
                customer_qb_id = invoice.metadata.get("quickbooks_customer_id")

        # If no mapping found, try to find customer by name in QuickBooks
        if not customer_qb_id and invoice.client_id:
            try:
                customer_name = invoice.client.name if invoice.client else None
                if customer_name:
                    # Query QuickBooks for customer by DisplayName
                    # QuickBooks query syntax: SELECT * FROM Customer WHERE DisplayName = 'CustomerName'
                    # URL encode the query parameter
                    from urllib.parse import quote

                    # Escape single quotes for SQL (replace ' with '')
                    escaped_name = customer_name.replace("'", "''")
                    query = f"SELECT * FROM Customer WHERE DisplayName = '{escaped_name}'"
                    query_url = f"/v3/company/{realm_id}/query?query={quote(query)}"

                    customers_response = self._api_request("GET", query_url, access_token, realm_id)

                    if customers_response and "QueryResponse" in customers_response:
                        customers = customers_response["QueryResponse"].get("Customer", [])
                        if customers:
                            # Handle both single customer and list of customers
                            if isinstance(customers, list):
                                if len(customers) > 0:
                                    customer_qb_id = customers[0].get("Id")
                            else:
                                customer_qb_id = customers.get("Id")

                            if customer_qb_id:
                                # Auto-save mapping for future use
                                if not self.integration.config:
                                    self.integration.config = {}
                                if "customer_mappings" not in self.integration.config:
                                    self.integration.config["customer_mappings"] = {}
                                self.integration.config["customer_mappings"][str(invoice.client_id)] = customer_qb_id
                                logger.info(
                                    f"Auto-mapped client {invoice.client_id} to QuickBooks customer {customer_qb_id}"
                                )
                    else:
                        logger.warning(
                            f"Customer '{customer_name}' not found in QuickBooks. Please configure customer mapping."
                        )
            except Exception as e:
                logger.error(f"Error looking up QuickBooks customer: {e}", exc_info=True)

        # If still no customer ID, we cannot create the invoice
        if not customer_qb_id:
            error_msg = f"Customer mapping not found for client {invoice.client_id}. Cannot create QuickBooks invoice."
            logger.error(error_msg)
            raise ValueError(error_msg)

        # Build QuickBooks invoice structure
        qb_invoice = {"CustomerRef": {"value": customer_qb_id}, "Line": []}

        # Add invoice items
        for item in invoice.items:
            try:
                # Try to get QuickBooks item ID from mapping
                item_qb_id = item_mapping.get(str(item.id))
                if not item_qb_id and isinstance(item_mapping.get(item.description), dict):
                    item_qb_id = item_mapping.get(item.description, {}).get("id")

                item_qb_name = item.description or "Service"

                # If no mapping, try to find item by name in QuickBooks
                if not item_qb_id:
                    try:
                        # Query QuickBooks for item by Name
                        from urllib.parse import quote

                        # Escape single quotes for SQL (replace ' with '')
                        escaped_name = item_qb_name.replace("'", "''")
                        query = f"SELECT * FROM Item WHERE Name = '{escaped_name}'"
                        query_url = f"/v3/company/{realm_id}/query?query={quote(query)}"

                        items_response = self._api_request("GET", query_url, access_token, realm_id)

                        if items_response and "QueryResponse" in items_response:
                            items = items_response["QueryResponse"].get("Item", [])
                            if items:
                                # Handle both single item and list of items
                                if isinstance(items, list):
                                    if len(items) > 0:
                                        item_qb_id = items[0].get("Id")
                                else:
                                    item_qb_id = items.get("Id")

                                if item_qb_id:
                                    # Auto-save mapping for future use
                                    if "item_mappings" not in self.integration.config:
                                        self.integration.config["item_mappings"] = {}
                                    self.integration.config["item_mappings"][str(item.id)] = item_qb_id
                                    logger.info(f"Auto-mapped invoice item {item.id} to QuickBooks item {item_qb_id}")
                    except Exception as e:
                        logger.warning(f"Error looking up QuickBooks item '{item_qb_name}': {e}")

                # Build line item
                line_item = {
                    "Amount": float(item.quantity * item.unit_price),
                    "DetailType": "SalesItemLineDetail",
                    "SalesItemLineDetail": {
                        "Qty": float(item.quantity),
                        "UnitPrice": float(item.unit_price),
                    },
                }

                if item_qb_id:
                    line_item["SalesItemLineDetail"]["ItemRef"] = {
                        "value": item_qb_id,
                        "name": item_qb_name,
                    }
                else:
                    # Use description as item name (QuickBooks will use or create item)
                    line_item["SalesItemLineDetail"]["ItemRef"] = {
                        "name": item_qb_name,
                    }
                    logger.warning(
                        f"Item mapping not found for invoice item {item.id}. Using description as item name."
                    )

                qb_invoice["Line"].append(line_item)
            except Exception as e:
                logger.error(f"Error processing invoice item {item.id}: {e}", exc_info=True)
                # Continue with other items instead of failing completely
                continue

        # Validate invoice has at least one line item
        if not qb_invoice["Line"]:
            error_msg = "Invoice has no valid line items"
            logger.error(error_msg)
            raise ValueError(error_msg)

        # Add invoice date and due date
        if invoice.created_at:
            qb_invoice["TxnDate"] = invoice.created_at.strftime("%Y-%m-%d")
        if invoice.due_date:
            qb_invoice["DueDate"] = invoice.due_date.strftime("%Y-%m-%d")

        endpoint = f"/v3/company/{realm_id}/invoice"
        result = self._api_request("POST", endpoint, access_token, realm_id, json_data=qb_invoice)

        if not result:
            raise ValueError("Failed to create invoice in QuickBooks - no response from API")

        # Validate response
        if "Invoice" not in result:
            raise ValueError(f"Invalid response from QuickBooks API: {result}")

        return result

    def _create_quickbooks_expense(self, expense, access_token: str, realm_id: str) -> Optional[Dict]:
        """Create expense in QuickBooks"""
        # Get account mapping from integration config
        account_mapping = self.integration.config.get("account_mappings", {}) if self.integration else {}
        default_expense_account = (
            self.integration.config.get("default_expense_account_id") if self.integration else None
        )

        # Try to get account ID from expense category mapping or use default
        account_id = default_expense_account
        if expense.category_id:
            account_id = account_mapping.get(str(expense.category_id), default_expense_account)
        elif hasattr(expense, "metadata") and expense.metadata:
            account_id = expense.metadata.get("quickbooks_account_id", default_expense_account)

        # If no account ID found, try to find or use default expense account
        if not account_id:
            try:
                # Query for default expense accounts
                from urllib.parse import quote

                query = "SELECT * FROM Account WHERE AccountType = 'Expense' AND Active = true MAXRESULTS 1"
                query_url = f"/v3/company/{realm_id}/query?query={quote(query)}"

                accounts_response = self._api_request("GET", query_url, access_token, realm_id)

                if accounts_response and "QueryResponse" in accounts_response:
                    accounts = accounts_response["QueryResponse"].get("Account", [])
                    if accounts:
                        if isinstance(accounts, list):
                            if len(accounts) > 0:
                                account_id = accounts[0].get("Id")
                        else:
                            account_id = accounts.get("Id")

                if account_id:
                    # Auto-save mapping for future use if we found an account
                    if expense.category_id:
                        if not self.integration.config:
                            self.integration.config = {}
                        if "account_mappings" not in self.integration.config:
                            self.integration.config["account_mappings"] = {}
                        self.integration.config["account_mappings"][str(expense.category_id)] = account_id
                        logger.info(
                            f"Auto-mapped expense category {expense.category_id} to QuickBooks account {account_id}"
                        )
                else:
                    # No account found - require configuration
                    error_msg = f"No expense account found for expense {expense.id}. Please configure account mapping or set default_expense_account_id in integration config."
                    logger.error(error_msg)
                    raise ValueError(error_msg)
            except ValueError:
                # Re-raise ValueError (our own error)
                raise
            except Exception as e:
                logger.error(f"Error looking up QuickBooks expense account: {e}", exc_info=True)
                # If we have a default, use it; otherwise fail
                if default_expense_account:
                    account_id = default_expense_account
                    logger.warning(f"Using default expense account {account_id} due to lookup error")
                else:
                    error_msg = f"Failed to determine QuickBooks account for expense {expense.id}. Please configure account mapping or default_expense_account_id."
                    raise ValueError(error_msg)

        # Build QuickBooks expense structure
        qb_expense = {
            "PaymentType": "Cash",
            "AccountRef": {"value": account_id},
            "Line": [
                {
                    "Amount": float(expense.amount),
                    "DetailType": "AccountBasedExpenseLineDetail",
                    "AccountBasedExpenseLineDetail": {"AccountRef": {"value": account_id}},
                }
            ],
        }

        # Add vendor if available
        if expense.vendor:
            qb_expense["EntityRef"] = {"name": expense.vendor}

        # Add expense date
        if expense.date:
            qb_expense["TxnDate"] = expense.date.strftime("%Y-%m-%d")

        # Add memo/description
        if expense.description:
            qb_expense["Line"][0]["Description"] = expense.description

        endpoint = f"/v3/company/{realm_id}/purchase"
        result = self._api_request("POST", endpoint, access_token, realm_id, json_data=qb_expense)

        if not result:
            raise ValueError("Failed to create expense in QuickBooks - no response from API")

        # Validate response
        if "Purchase" not in result:
            raise ValueError(f"Invalid response from QuickBooks API: {result}")

        return result

    def get_config_schema(self) -> Dict[str, Any]:
        """Get configuration schema."""
        return {
            "fields": [
                {
                    "name": "realm_id",
                    "type": "string",
                    "label": "Company ID (Realm ID)",
                    "required": True,
                    "placeholder": "123456789",
                    "description": "QuickBooks company ID (realm ID)",
                    "help": "Find your company ID in QuickBooks after connecting. It's automatically set during OAuth.",
                },
                {
                    "name": "use_sandbox",
                    "type": "boolean",
                    "label": "Use Sandbox",
                    "default": True,
                    "description": "Use QuickBooks sandbox environment for testing",
                },
                {
                    "name": "sync_direction",
                    "type": "select",
                    "label": "Sync Direction",
                    "options": [
                        {"value": "quickbooks_to_timetracker", "label": "QuickBooks → TimeTracker (Import only)"},
                        {"value": "timetracker_to_quickbooks", "label": "TimeTracker → QuickBooks (Export only)"},
                        {"value": "bidirectional", "label": "Bidirectional (Two-way sync)"},
                    ],
                    "default": "timetracker_to_quickbooks",
                    "description": "Choose how data flows between QuickBooks and TimeTracker",
                },
                {
                    "name": "sync_items",
                    "type": "array",
                    "label": "Items to Sync",
                    "options": [
                        {"value": "invoices", "label": "Invoices"},
                        {"value": "expenses", "label": "Expenses"},
                        {"value": "payments", "label": "Payments"},
                        {"value": "customers", "label": "Customers"},
                    ],
                    "default": ["invoices", "expenses"],
                    "description": "Select which items to synchronize",
                },
                {
                    "name": "sync_invoices",
                    "type": "boolean",
                    "label": "Sync Invoices",
                    "default": True,
                    "description": "Enable invoice synchronization",
                },
                {
                    "name": "sync_expenses",
                    "type": "boolean",
                    "label": "Sync Expenses",
                    "default": True,
                    "description": "Enable expense synchronization",
                },
                {
                    "name": "auto_sync",
                    "type": "boolean",
                    "label": "Auto Sync",
                    "default": False,
                    "description": "Automatically sync when invoices or expenses are created/updated",
                },
                {
                    "name": "sync_interval",
                    "type": "select",
                    "label": "Sync Schedule",
                    "options": [
                        {"value": "manual", "label": "Manual only"},
                        {"value": "hourly", "label": "Every hour"},
                        {"value": "daily", "label": "Daily"},
                    ],
                    "default": "manual",
                    "description": "How often to automatically sync data",
                },
                {
                    "name": "default_expense_account_id",
                    "type": "string",
                    "label": "Default Expense Account ID",
                    "required": False,
                    "default": "1",
                    "description": "QuickBooks account ID to use for expenses when no mapping is configured",
                    "help": "Find account IDs in QuickBooks Chart of Accounts",
                },
                {
                    "name": "customer_mappings",
                    "type": "json",
                    "label": "Customer Mappings",
                    "required": False,
                    "placeholder": '{"1": "qb_customer_id_123", "2": "qb_customer_id_456"}',
                    "description": "JSON mapping of TimeTracker client IDs to QuickBooks customer IDs",
                    "help": 'Map your TimeTracker clients to QuickBooks customers. Format: {"timetracker_client_id": "quickbooks_customer_id"}',
                },
                {
                    "name": "item_mappings",
                    "type": "json",
                    "label": "Item Mappings",
                    "required": False,
                    "placeholder": '{"service_1": "qb_item_id_123"}',
                    "description": "JSON mapping of TimeTracker invoice items to QuickBooks items",
                    "help": "Map your TimeTracker services/products to QuickBooks items",
                },
                {
                    "name": "account_mappings",
                    "type": "json",
                    "label": "Account Mappings",
                    "required": False,
                    "placeholder": '{"expense_category_1": "qb_account_id_123"}',
                    "description": "JSON mapping of TimeTracker expense category IDs to QuickBooks account IDs",
                    "help": "Map your TimeTracker expense categories to QuickBooks accounts",
                },
            ],
            "required": ["realm_id"],
            "sections": [
                {
                    "title": "Connection Settings",
                    "description": "Configure your QuickBooks connection",
                    "fields": ["realm_id", "use_sandbox"],
                },
                {
                    "title": "Sync Settings",
                    "description": "Configure what and how to sync",
                    "fields": [
                        "sync_direction",
                        "sync_items",
                        "sync_invoices",
                        "sync_expenses",
                        "auto_sync",
                        "sync_interval",
                    ],
                },
                {
                    "title": "Data Mapping",
                    "description": "Map TimeTracker data to QuickBooks",
                    "fields": ["default_expense_account_id", "customer_mappings", "item_mappings", "account_mappings"],
                },
            ],
            "sync_settings": {
                "enabled": True,
                "auto_sync": False,
                "sync_interval": "manual",
                "sync_direction": "timetracker_to_quickbooks",
                "sync_items": ["invoices", "expenses"],
            },
        }
