# Copyright 2026 Flyto2. Licensed under Apache-2.0. See LICENSE.

"""
Stripe Payment Integration Modules

Provides payment processing operations with Stripe.
"""
import logging
import os
from typing import Any, Dict

from ...base import BaseModule
from ...registry import register_module
from ....constants import APIEndpoints, EnvVars


logger = logging.getLogger(__name__)


def _simplify_charges(charges_data):
    """Extract essential fields from Stripe charge list."""
    return [{
        'id': c['id'], 'amount': c['amount'], 'currency': c['currency'],
        'status': c['status'], 'paid': c['paid'], 'created': c['created'],
        'description': c.get('description'),
    } for c in charges_data]


@register_module(
    module_id='payment.stripe.create_payment',
    can_connect_to=['*'],
    can_receive_from=['data.*', 'http.*', 'flow.*', 'start'],
    version='1.0.0',
    category='productivity',
    subcategory='payment',
    tags=['stripe', 'payment', 'charge', 'checkout', 'ssrf_protected'],
    label='Stripe Create Payment',
    label_key='modules.payment.stripe.create_payment.label',
    description='Create a payment intent with Stripe',
    description_key='modules.payment.stripe.create_payment.description',
    icon='CreditCard',
    color='#635BFF',

    # Connection types
    input_types=['json'],
    output_types=['json'],

    # Phase 2: Execution settings
    timeout_ms=30000,
    retryable=True,
    max_retries=2,
    concurrent_safe=True,

    # Phase 2: Security settings
    requires_credentials=True,
    credential_keys=['STRIPE_API_KEY'],
    handles_sensitive_data=True,
    required_permissions=['payment.process'],

    params_schema={
        'api_key': {
            'type': 'string',
            'label': 'API Key',
            'label_key': 'modules.payment.stripe.create_payment.params.api_key.label',
            'description': 'Stripe secret key (or use STRIPE_API_KEY env)',
            'description_key': 'modules.payment.stripe.create_payment.params.api_key.description',
            'required': False,
            'sensitive': True
        ,
            'placeholder': 'sk-...',
},
        'amount': {
            'type': 'number',
            'label': 'Amount',
            'label_key': 'modules.payment.stripe.create_payment.params.amount.label',
            'description': 'Amount in cents (e.g. 1000 for $10.00)',
            'description_key': 'modules.payment.stripe.create_payment.params.amount.description',
            'required': True,
            'min': 1
        },
        'currency': {
            'type': 'string',
            'label': 'Currency',
            'label_key': 'modules.payment.stripe.create_payment.params.currency.label',
            'description': 'Three-letter currency code (e.g. usd, eur)',
            'description_key': 'modules.payment.stripe.create_payment.params.currency.description',
            'default': 'usd',
            'required': False
        ,
            'placeholder': 'usd',
},
        'description': {
            'type': 'string',
            'label': 'Description',
            'label_key': 'modules.payment.stripe.create_payment.params.description.label',
            'description': 'Payment description',
            'description_key': 'modules.payment.stripe.create_payment.params.description.description',
            'required': False
        ,
            'placeholder': 'Description text',
},
        'customer': {
            'type': 'string',
            'label': 'Customer ID',
            'label_key': 'modules.payment.stripe.create_payment.params.customer.label',
            'description': 'Stripe customer ID (optional)',
            'description_key': 'modules.payment.stripe.create_payment.params.customer.description',
            'required': False
        ,
            'placeholder': 'Enter customer...',
}
    },
    output_schema={
        'id': {'type': 'string', 'description': 'Unique identifier',
                'description_key': 'modules.payment.stripe.create_payment.output.id.description'},
        'amount': {'type': 'number', 'description': 'Payment amount',
                'description_key': 'modules.payment.stripe.create_payment.output.amount.description'},
        'currency': {'type': 'string', 'description': 'Currency code',
                'description_key': 'modules.payment.stripe.create_payment.output.currency.description'},
        'status': {'type': 'string', 'description': 'Operation status (success/error)',
                'description_key': 'modules.payment.stripe.create_payment.output.status.description'},
        'client_secret': {'type': 'string', 'description': 'Client secret for payment',
                'description_key': 'modules.payment.stripe.create_payment.output.client_secret.description'}
    },
    examples=[
        {
            'title': 'Create $50 payment',
            'params': {
                'amount': 5000,
                'currency': 'usd',
                'description': 'Product purchase'
            }
        },
        {
            'title': 'Create payment for customer',
            'params': {
                'amount': 2999,
                'currency': 'usd',
                'customer': 'cus_XXXXXXXXXXXXXXX',
                'description': 'Subscription payment'
            }
        }
    ],
    author='Flyto Team',
    license='MIT'
)
class StripeCreatePaymentModule(BaseModule):
    """Stripe Create Payment Intent Module"""

    def validate_params(self) -> None:
        self.api_key = self.params.get('api_key')
        self.amount = self.params.get('amount')
        self.currency = self.params.get('currency', 'usd')
        self.description = self.params.get('description')
        self.customer = self.params.get('customer')

        if not self.api_key:
            self.api_key = os.environ.get(EnvVars.STRIPE_API_KEY)
            if not self.api_key:
                raise ValueError(f"api_key or {EnvVars.STRIPE_API_KEY} environment variable is required")

        if not self.amount:
            raise ValueError("amount is required")

    async def execute(self) -> Any:
        try:
            import aiohttp

            # Build request body
            data = {
                'amount': int(self.amount),
                'currency': self.currency
            }
            if self.description:
                data['description'] = self.description
            if self.customer:
                data['customer'] = self.customer

            # Make API request
            headers = {
                'Authorization': f'Bearer {self.api_key}',
                'Content-Type': 'application/x-www-form-urlencoded'
            }

            # SECURITY: Set timeout to prevent hanging API calls
            timeout = aiohttp.ClientTimeout(total=30, connect=10)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.post(
                    APIEndpoints.STRIPE_PAYMENT_INTENTS,
                    headers=headers,
                    data=data
                ) as response:
                    if response.status != 200:
                        error_text = await response.text()
                        raise RuntimeError(f"Stripe API error ({response.status}): {error_text}")

                    result = await response.json()

                    return {
                        "id": result['id'],
                        "amount": result['amount'],
                        "currency": result['currency'],
                        "status": result['status'],
                        "client_secret": result.get('client_secret')
                    }

        except Exception as e:
            raise RuntimeError(f"Stripe payment creation error: {str(e)}")


@register_module(
    module_id='payment.stripe.get_customer',
    can_connect_to=['*'],
    can_receive_from=['data.*', 'http.*', 'flow.*', 'start'],
    version='1.0.0',
    category='productivity',
    subcategory='payment',
    tags=['stripe', 'customer', 'retrieve', 'ssrf_protected'],
    label='Stripe Get Customer',
    label_key='modules.payment.stripe.get_customer.label',
    description='Retrieve customer information from Stripe',
    description_key='modules.payment.stripe.get_customer.description',
    icon='User',
    color='#635BFF',

    # Connection types
    input_types=['text'],
    output_types=['json'],

    # Phase 2: Execution settings
    timeout_ms=15000,
    retryable=True,
    max_retries=3,
    concurrent_safe=True,

    # Phase 2: Security settings
    requires_credentials=True,
    credential_keys=['STRIPE_API_KEY'],
    handles_sensitive_data=True,
    required_permissions=['payment.process'],

    params_schema={
        'api_key': {
            'type': 'string',
            'label': 'API Key',
            'label_key': 'modules.payment.stripe.get_customer.params.api_key.label',
            'description': 'Stripe secret key (or use STRIPE_API_KEY env)',
            'description_key': 'modules.payment.stripe.get_customer.params.api_key.description',
            'placeholder': 'sk-...',
            'required': False,
            'sensitive': True
        },
        'customer_id': {
            'type': 'string',
            'label': 'Customer ID',
            'label_key': 'modules.payment.stripe.get_customer.params.customer_id.label',
            'description': 'Stripe customer ID',
            'description_key': 'modules.payment.stripe.get_customer.params.customer_id.description',
            'required': True
        ,
            'placeholder': 'cus_xxxxx',
}
    },
    output_schema={
        'id': {'type': 'string', 'description': 'Unique identifier'},
        'email': {'type': 'string', 'description': 'Email address'},
        'name': {'type': 'string', 'description': 'Name of the item'},
        'created': {'type': 'number', 'description': 'Creation timestamp'},
        'balance': {'type': 'number', 'description': 'Account balance'}
    },
    examples=[
        {
            'title': 'Get customer info',
            'params': {
                'customer_id': 'cus_XXXXXXXXXXXXXXX'
            }
        }
    ],
    author='Flyto Team',
    license='MIT'
)
class StripeGetCustomerModule(BaseModule):
    """Stripe Get Customer Module"""

    def validate_params(self) -> None:
        self.api_key = self.params.get('api_key')
        self.customer_id = self.params.get('customer_id')

        if not self.api_key:
            self.api_key = os.environ.get(EnvVars.STRIPE_API_KEY)
            if not self.api_key:
                raise ValueError(f"api_key or {EnvVars.STRIPE_API_KEY} environment variable is required")

        if not self.customer_id:
            raise ValueError("customer_id is required")

    async def execute(self) -> Any:
        try:
            import aiohttp

            # Make API request
            headers = {
                'Authorization': f'Bearer {self.api_key}'
            }

            # SECURITY: Set timeout to prevent hanging API calls
            timeout = aiohttp.ClientTimeout(total=30, connect=10)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(
                    f"{APIEndpoints.STRIPE_CUSTOMERS}/{self.customer_id}",
                    headers=headers
                ) as response:
                    if response.status != 200:
                        error_text = await response.text()
                        raise RuntimeError(f"Stripe API error ({response.status}): {error_text}")

                    result = await response.json()

                    return {
                        "id": result['id'],
                        "email": result.get('email'),
                        "name": result.get('name'),
                        "created": result.get('created'),
                        "balance": result.get('balance', 0)
                    }

        except Exception as e:
            raise RuntimeError(f"Stripe get customer error: {str(e)}")


@register_module(
    module_id='payment.stripe.list_charges',
    can_connect_to=['*'],
    can_receive_from=['data.*', 'http.*', 'flow.*', 'start'],
    version='1.0.0',
    category='productivity',
    subcategory='payment',
    tags=['stripe', 'charges', 'list', 'transactions', 'ssrf_protected'],
    label='Stripe List Charges',
    label_key='modules.payment.stripe.list_charges.label',
    description='List recent charges from Stripe',
    description_key='modules.payment.stripe.list_charges.description',
    icon='List',
    color='#635BFF',

    # Connection types
    input_types=['json'],
    output_types=['array', 'json'],

    # Phase 2: Execution settings
    timeout_ms=20000,
    retryable=True,
    max_retries=3,
    concurrent_safe=True,

    # Phase 2: Security settings
    requires_credentials=True,
    credential_keys=['STRIPE_API_KEY'],
    handles_sensitive_data=True,
    required_permissions=['payment.process'],

    params_schema={
        'api_key': {
            'type': 'string',
            'label': 'API Key',
            'label_key': 'modules.payment.stripe.list_charges.params.api_key.label',
            'description': 'Stripe secret key (or use STRIPE_API_KEY env)',
            'description_key': 'modules.payment.stripe.list_charges.params.api_key.description',
            'placeholder': 'sk-...',
            'required': False,
            'sensitive': True
        },
        'limit': {
            'type': 'number',
            'label': 'Limit',
            'label_key': 'modules.payment.stripe.list_charges.params.limit.label',
            'description': 'Number of charges to return (1-100)',
            'description_key': 'modules.payment.stripe.list_charges.params.limit.description',
            'default': 10,
            'min': 1,
            'max': 100,
            'required': False
        },
        'customer': {
            'type': 'string',
            'label': 'Customer ID',
            'label_key': 'modules.payment.stripe.list_charges.params.customer.label',
            'description': 'Filter by customer ID (optional)',
            'description_key': 'modules.payment.stripe.list_charges.params.customer.description',
            'placeholder': 'cus_xxxxx',
            'required': False
        }
    },
    output_schema={
        'charges': {'type': 'array', 'description': 'The charges'},
        'count': {'type': 'number', 'description': 'Number of items'},
        'has_more': {'type': 'boolean', 'description': 'The has more'}
    },
    examples=[
        {
            'title': 'List recent charges',
            'params': {
                'limit': 20
            }
        },
        {
            'title': 'List customer charges',
            'params': {
                'customer': 'cus_XXXXXXXXXXXXXXX',
                'limit': 50
            }
        }
    ],
    author='Flyto Team',
    license='MIT'
)
class StripeListChargesModule(BaseModule):
    """Stripe List Charges Module"""

    def validate_params(self) -> None:
        self.api_key = self.params.get('api_key')
        self.limit = self.params.get('limit', 10)
        self.customer = self.params.get('customer')

        if not self.api_key:
            self.api_key = os.environ.get(EnvVars.STRIPE_API_KEY)
            if not self.api_key:
                raise ValueError(f"api_key or {EnvVars.STRIPE_API_KEY} environment variable is required")

    async def execute(self) -> Any:
        try:
            import aiohttp

            params = {'limit': self.limit}
            if self.customer:
                params['customer'] = self.customer
            headers = {'Authorization': f'Bearer {self.api_key}'}

            timeout = aiohttp.ClientTimeout(total=30, connect=10)
            async with aiohttp.ClientSession(timeout=timeout) as session:
                async with session.get(APIEndpoints.STRIPE_CHARGES, headers=headers, params=params) as response:
                    if response.status != 200:
                        error_text = await response.text()
                        raise RuntimeError(f"Stripe API error ({response.status}): {error_text}")
                    result = await response.json()

            charges = _simplify_charges(result['data'])
            return {"charges": charges, "count": len(charges), "has_more": result.get('has_more', False)}
        except Exception as e:
            raise RuntimeError(f"Stripe list charges error: {str(e)}")
