import requests
from flask import current_app


def _call(method: str, params: dict) -> dict:
    """Base JSON-RPC style call to the e-računi API."""
    cfg = current_app.config
    url      = cfg.get('ERACUNI_URL') or ''
    username = cfg.get('ERACUNI_USERNAME') or ''
    password = cfg.get('ERACUNI_PASSWORD') or ''
    token    = cfg.get('ERACUNI_TOKEN') or ''

    if not url:
        raise RuntimeError(
            'ERACUNI_URL is not configured. '
            'Go to Settings → e-Računi and save your credentials.'
        )
    if not username or not password:
        raise RuntimeError(
            'ERACUNI_USERNAME or ERACUNI_PASSWORD is not configured. '
            'Go to Settings → e-Računi and save your credentials.'
        )

    payload = {
        "method": method,
        "parameters": params,
        "username": username,
        "md5pass": password,
        "token": token,
    }
    try:
        resp = requests.post(url, json=payload, timeout=30)
    except requests.exceptions.SSLError as e:
        raise RuntimeError(
            f'SSL certificate error connecting to e-računi ({url}). '
            f'The server may have an outdated CA bundle. Details: {e}'
        ) from e
    except requests.exceptions.ConnectionError as e:
        raise RuntimeError(
            f'Cannot connect to e-računi at {url}. '
            f'Check the URL and that the server can reach it. Details: {e}'
        ) from e
    except requests.exceptions.Timeout:
        raise RuntimeError(f'e-računi request timed out after 30s (URL: {url})')

    resp.raise_for_status()
    data = resp.json()
    # API returns {"response": {"result": ...}}
    return data.get('response', {}).get('result', data)


def get_orders(date_from: str) -> list:
    """Fetch a list of sales orders from date_from (YYYY-MM-DD).

    Returns list of order dicts.
    """
    result = _call('SalesOrderList', {'dateFrom': date_from})
    if isinstance(result, list):
        return result
    # Some API versions wrap the list
    if isinstance(result, dict):
        return result.get('salesOrders', result.get('orders', []))
    return []


def get_orders_by_status(status: str) -> list:
    """Fetch all sales orders with a given status (e.g. 'Draft', 'PartialDelivery')."""
    result = _call('SalesOrderList', {'status': status})
    if isinstance(result, list):
        return result
    if isinstance(result, dict):
        return result.get('salesOrders', result.get('orders', []))
    return []


def get_order(number: str) -> dict:
    """Fetch a single order by number (operator='Web Shop')."""
    result = _call('SalesOrderGet', {
        'number': number,
        'operator': 'Web Shop',
    })
    if isinstance(result, dict):
        return result.get('salesOrder', result)
    return {}


def update_order(number: str, **kwargs) -> dict:
    """Update an order. Supported kwargs: status, buyerTaxNumber, vatTransactionType."""
    params = {'number': number}
    params.update(kwargs)
    return _call('SalesOrderUpdate', params)


def create_invoice(number: str) -> str:
    """Create an invoice from a sales order. Returns the documentID string."""
    result = _call('SalesOrderCreateInvoice', {'number': number})
    if isinstance(result, dict):
        return str(result.get('documentID', result.get('id', '')))
    return str(result)


def get_invoice(document_id: str) -> dict:
    """Fetch a sales invoice by document ID."""
    result = _call('SalesInvoiceGet', {'documentID': document_id})
    if isinstance(result, dict):
        return result.get('salesInvoice', result)
    return {}


def get_invoice_pdf(document_id: str) -> bytes:
    """Fetch the PDF bytes of a sales invoice."""
    import base64
    result = _call('SalesInvoiceGetPDF', {'documentID': document_id})
    # API may return base64-encoded PDF string or raw bytes representation
    if isinstance(result, str):
        return base64.b64decode(result)
    if isinstance(result, dict):
        pdf_b64 = result.get('pdf', result.get('content', ''))
        return base64.b64decode(pdf_b64)
    return b''


def get_delivery_note_pdf(document_id: str) -> bytes:
    """Fetch the PDF bytes of a delivery note."""
    import base64
    result = _call('DeliveryNoteGetPDF', {'documentID': document_id})
    if isinstance(result, str):
        return base64.b64decode(result)
    if isinstance(result, dict):
        pdf_b64 = result.get('pdf', result.get('content', ''))
        return base64.b64decode(pdf_b64)
    return b''


def get_product_raw(product_code: str) -> dict:
    """Fetch a single product's full raw API response by productCode.

    Tries ProductGet first; falls back to scanning ProductList if the API
    doesn't support single-item fetches.
    """
    try:
        result = _call('ProductGet', {'productCode': product_code})
        if isinstance(result, dict) and result:
            return result.get('product', result)
    except Exception:
        pass
    # Fallback: scan full list
    try:
        all_products = get_products()
        for p in all_products:
            if p.get('productCode') == product_code:
                return p
    except Exception:
        pass
    return {}


def get_products() -> list:
    """Fetch all active products from e-računi. Returns list of product dicts."""
    result = _call('ProductList', {})
    if isinstance(result, list):
        return result
    if isinstance(result, dict):
        return result.get('products', result.get('items', []))
    return []


def get_delivery_note_list(number: str) -> list:
    """Return list of delivery notes for a sales order number."""
    result = _call('DeliveryNoteList', {'number': number})
    if isinstance(result, list):
        return result
    if isinstance(result, dict):
        return result.get('deliveryNotes', [])
    return []
