"""Settings API routes."""

from flask import Blueprint, request
from flask_jwt_extended import jwt_required

from shopdb.extensions import db, cache
from shopdb.core.models import Setting, AuditLog
from shopdb.utils.responses import success_response, error_response, ErrorCodes

settings_bp = Blueprint('settings', __name__)

# Cache key for settings
SETTINGS_CACHE_KEY = 'system_settings'
SETTINGS_CACHE_TTL = 300  # 5 minutes


def get_cached_settings():
    """Get all settings from cache or database."""
    cached = cache.get(SETTINGS_CACHE_KEY)
    if cached is not None:
        return cached

    settings = Setting.query.all()
    result = {s.key: s.get_typed_value() for s in settings}
    cache.set(SETTINGS_CACHE_KEY, result, timeout=SETTINGS_CACHE_TTL)
    return result


def invalidate_settings_cache():
    """Clear the settings cache."""
    cache.delete(SETTINGS_CACHE_KEY)


@settings_bp.route('', methods=['GET'])
@jwt_required(optional=True)
def list_settings():
    """List all settings, optionally filtered by category."""
    category = request.args.get('category')

    query = Setting.query
    if category:
        query = query.filter_by(category=category)

    settings = query.order_by(Setting.category, Setting.key).all()
    return success_response([s.to_dict() for s in settings])


@settings_bp.route('/<key>', methods=['GET'])
@jwt_required(optional=True)
def get_setting(key: str):
    """Get a single setting by key."""
    setting = Setting.query.filter_by(key=key).first()

    if not setting:
        return error_response(ErrorCodes.NOT_FOUND, f'Setting {key} not found', http_code=404)

    return success_response(setting.to_dict())


@settings_bp.route('/<key>', methods=['PUT'])
@jwt_required()
def update_setting(key: str):
    """Update a setting value."""
    data = request.get_json()

    if data is None or 'value' not in data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'value is required')

    setting = Setting.query.filter_by(key=key).first()

    if not setting:
        return error_response(ErrorCodes.NOT_FOUND, f'Setting {key} not found', http_code=404)

    # Track old value for audit
    old_value = setting.value

    # Convert value to string for storage
    value = data['value']
    if isinstance(value, bool):
        setting.value = 'true' if value else 'false'
    else:
        setting.value = str(value) if value is not None else None

    # Audit log (mask sensitive values)
    is_sensitive = 'password' in key or 'token' in key or 'secret' in key
    AuditLog.log('updated', 'Setting', entityname=key, changes={
        'value': {
            'old': '***' if is_sensitive else old_value,
            'new': '***' if is_sensitive else setting.value
        }
    })

    db.session.commit()
    invalidate_settings_cache()

    return success_response(setting.to_dict(), message='Setting updated')


@settings_bp.route('', methods=['POST'])
@jwt_required()
def create_setting():
    """Create a new setting (admin only)."""
    data = request.get_json()

    if not data or not data.get('key'):
        return error_response(ErrorCodes.VALIDATION_ERROR, 'key is required')

    if Setting.query.filter_by(key=data['key']).first():
        return error_response(ErrorCodes.CONFLICT, f"Setting '{data['key']}' already exists", http_code=409)

    value = data.get('value')
    if isinstance(value, bool):
        value_str = 'true' if value else 'false'
    else:
        value_str = str(value) if value is not None else None

    setting = Setting(
        key=data['key'],
        value=value_str,
        valuetype=data.get('valuetype', 'string'),
        category=data.get('category', 'general'),
        description=data.get('description')
    )

    db.session.add(setting)
    db.session.commit()
    invalidate_settings_cache()

    return success_response(setting.to_dict(), message='Setting created', http_code=201)


@settings_bp.route('/seed', methods=['POST'])
@jwt_required()
def seed_default_settings():
    """Seed default settings if they don't exist."""
    defaults = [
        # Zabbix integration
        {
            'key': 'zabbix_enabled',
            'value': 'false',
            'valuetype': 'boolean',
            'category': 'integrations',
            'description': 'Enable Zabbix integration for printer supply monitoring'
        },
        {
            'key': 'zabbix_url',
            'value': '',
            'valuetype': 'string',
            'category': 'integrations',
            'description': 'Zabbix API URL (e.g., http://zabbix.example.com:8080)'
        },
        {
            'key': 'zabbix_token',
            'value': '',
            'valuetype': 'string',
            'category': 'integrations',
            'description': 'Zabbix API authentication token'
        },
        # Email/SMTP settings
        {
            'key': 'smtp_enabled',
            'value': 'false',
            'valuetype': 'boolean',
            'category': 'email',
            'description': 'Enable email notifications and alerts'
        },
        {
            'key': 'smtp_host',
            'value': '',
            'valuetype': 'string',
            'category': 'email',
            'description': 'SMTP server hostname'
        },
        {
            'key': 'smtp_port',
            'value': '587',
            'valuetype': 'integer',
            'category': 'email',
            'description': 'SMTP server port (usually 587 for TLS, 465 for SSL, 25 for unencrypted)'
        },
        {
            'key': 'smtp_username',
            'value': '',
            'valuetype': 'string',
            'category': 'email',
            'description': 'SMTP authentication username'
        },
        {
            'key': 'smtp_password',
            'value': '',
            'valuetype': 'string',
            'category': 'email',
            'description': 'SMTP authentication password'
        },
        {
            'key': 'smtp_use_tls',
            'value': 'true',
            'valuetype': 'boolean',
            'category': 'email',
            'description': 'Use TLS encryption for SMTP connection'
        },
        {
            'key': 'smtp_from_address',
            'value': '',
            'valuetype': 'string',
            'category': 'email',
            'description': 'From address for outgoing emails'
        },
        {
            'key': 'smtp_from_name',
            'value': 'ShopDB',
            'valuetype': 'string',
            'category': 'email',
            'description': 'From name for outgoing emails'
        },
        {
            'key': 'alert_recipients',
            'value': '',
            'valuetype': 'string',
            'category': 'email',
            'description': 'Default email recipients for alerts (comma-separated)'
        },
        # Audit log settings
        {
            'key': 'audit_retention_days',
            'value': '90',
            'valuetype': 'integer',
            'category': 'audit',
            'description': 'Number of days to retain audit logs (0 = keep forever)'
        },
        # Authentication settings
        {
            'key': 'saml_enabled',
            'value': 'false',
            'valuetype': 'boolean',
            'category': 'auth',
            'description': 'Enable SAML SSO authentication'
        },
        {
            'key': 'saml_idp_metadata_url',
            'value': '',
            'valuetype': 'string',
            'category': 'auth',
            'description': 'SAML Identity Provider metadata URL'
        },
        {
            'key': 'saml_entity_id',
            'value': '',
            'valuetype': 'string',
            'category': 'auth',
            'description': 'SAML Service Provider entity ID (e.g., https://shopdb.example.com)'
        },
        {
            'key': 'saml_acs_url',
            'value': '',
            'valuetype': 'string',
            'category': 'auth',
            'description': 'SAML Assertion Consumer Service URL'
        },
        {
            'key': 'saml_allow_local_login',
            'value': 'true',
            'valuetype': 'boolean',
            'category': 'auth',
            'description': 'Allow local username/password login when SAML is enabled'
        },
        {
            'key': 'saml_auto_create_users',
            'value': 'true',
            'valuetype': 'boolean',
            'category': 'auth',
            'description': 'Automatically create users on first SAML login'
        },
        {
            'key': 'saml_admin_group',
            'value': '',
            'valuetype': 'string',
            'category': 'auth',
            'description': 'SAML group name that grants admin role'
        },
    ]

    created = 0
    for d in defaults:
        if not Setting.query.filter_by(key=d['key']).first():
            setting = Setting(**d)
            db.session.add(setting)
            created += 1

    db.session.commit()
    invalidate_settings_cache()

    return success_response({'created': created}, message=f'{created} default settings created')
