"""Dashboard defaults API: visitor-IP -> business-unit mapping.

CRUD for the mappings plus a resolve endpoint a kiosk/lobby dashboard calls to
auto-select its business unit from the display PC's IP.
"""

from flask import Blueprint, request
from flask_jwt_extended import jwt_required

from shopdb.extensions import db
from shopdb.core.models import DashboardDefault, BusinessUnit, AuditLog
from shopdb.utils.responses import success_response, error_response, ErrorCodes
from shopdb.utils.authz import require_role

dashboarddefaults_bp = Blueprint('dashboarddefaults', __name__)


def _request_ip():
    """Caller IP, honoring a single proxy hop via X-Forwarded-For."""
    forwarded = request.headers.get('X-Forwarded-For')
    if forwarded:
        return forwarded.split(',')[0].strip()
    return request.remote_addr


def _serialize(default):
    data = default.to_dict()
    data['businessunit'] = default.businessunit.businessunit \
        if default.businessunit else None
    return data


@dashboarddefaults_bp.route('/visitor-location', methods=['GET'])
def visitor_location():
    """Resolve the business unit for the calling display by its IP.

    Unauthenticated: kiosks/lobby displays hit this. Returns the mapped
    business unit, or a null businessunitid when the IP is not mapped.
    """
    ipaddress = request.args.get('ipaddress') or _request_ip()
    default = DashboardDefault.query.filter_by(
        ipaddress=ipaddress, isactive=True).first()
    if not default:
        return success_response({
            'ipaddress': ipaddress,
            'businessunitid': None,
            'businessunit': None,
        })
    return success_response({
        'ipaddress': ipaddress,
        'businessunitid': default.businessunitid,
        'businessunit': default.businessunit.businessunit
        if default.businessunit else None,
    })


@dashboarddefaults_bp.route('', methods=['GET'])
@jwt_required(optional=True)
def list_defaults():
    """List all visitor-IP -> business-unit mappings."""
    defaults = DashboardDefault.query.filter_by(isactive=True).order_by(
        DashboardDefault.ipaddress).all()
    return success_response([_serialize(d) for d in defaults])


@dashboarddefaults_bp.route('', methods=['POST'])
@jwt_required()
@require_role('admin')
def create_default():
    """Create a visitor-IP -> business-unit mapping."""
    data = request.get_json() or {}
    ipaddress = (data.get('ipaddress') or '').strip()
    businessunitid = data.get('businessunitid')

    if not ipaddress:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'ipaddress is required')
    if not businessunitid:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'businessunitid is required')
    if not db.session.get(BusinessUnit, businessunitid):
        return error_response(ErrorCodes.NOT_FOUND, 'Business unit not found',
                              http_code=404)
    if DashboardDefault.query.filter_by(ipaddress=ipaddress, isactive=True).first():
        return error_response(ErrorCodes.CONFLICT,
                              f"IP {ipaddress} is already mapped", http_code=409)

    default = DashboardDefault(ipaddress=ipaddress, businessunitid=businessunitid,
                               description=data.get('description'))
    db.session.add(default)
    db.session.flush()
    AuditLog.log('created', 'DashboardDefault', entityid=default.dashboarddefaultid,
                 entityname=ipaddress)
    db.session.commit()
    return success_response(_serialize(default), message='Mapping created',
                            http_code=201)


@dashboarddefaults_bp.route('/<int:default_id>', methods=['PUT'])
@jwt_required()
@require_role('admin')
def update_default(default_id):
    """Update a mapping."""
    default = db.session.get(DashboardDefault, default_id)
    if not default:
        return error_response(ErrorCodes.NOT_FOUND, 'Mapping not found', http_code=404)

    data = request.get_json() or {}
    if 'businessunitid' in data:
        if not db.session.get(BusinessUnit, data['businessunitid']):
            return error_response(ErrorCodes.NOT_FOUND, 'Business unit not found',
                                  http_code=404)
        default.businessunitid = data['businessunitid']
    if 'ipaddress' in data and data['ipaddress']:
        default.ipaddress = data['ipaddress'].strip()
    if 'description' in data:
        default.description = data['description']

    db.session.commit()
    return success_response(_serialize(default), message='Mapping updated')


@dashboarddefaults_bp.route('/<int:default_id>', methods=['DELETE'])
@jwt_required()
@require_role('admin')
def delete_default(default_id):
    """Delete (deactivate) a mapping."""
    default = db.session.get(DashboardDefault, default_id)
    if not default:
        return error_response(ErrorCodes.NOT_FOUND, 'Mapping not found', http_code=404)
    default.isactive = False
    db.session.commit()
    return success_response(message='Mapping deleted')
