"""Notifications plugin API endpoints - adapted to existing schema."""

from datetime import datetime
from flask import Blueprint, request
from flask_jwt_extended import jwt_required

from shopdb.extensions import db
from shopdb.utils.responses import (
    success_response,
    error_response,
    paginated_response,
    ErrorCodes
)
from shopdb.utils.pagination import get_pagination_params, paginate_query

from ..models import Notification, NotificationType

notifications_bp = Blueprint('notifications', __name__)


# =============================================================================
# Notification Types
# =============================================================================

@notifications_bp.route('/types', methods=['GET'])
def list_notification_types():
    """List all notification types."""
    page, per_page = get_pagination_params(request)

    query = NotificationType.query

    if request.args.get('active', 'true').lower() != 'false':
        query = query.filter(NotificationType.isactive == True)

    query = query.order_by(NotificationType.typename)

    items, total = paginate_query(query, page, per_page)
    data = [t.to_dict() for t in items]

    return paginated_response(data, page, per_page, total)


@notifications_bp.route('/types', methods=['POST'])
@jwt_required()
def create_notification_type():
    """Create a new notification type."""
    data = request.get_json()

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

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

    t = NotificationType(
        typename=data['typename'],
        typedescription=data.get('typedescription') or data.get('description'),
        typecolor=data.get('typecolor') or data.get('color', '#17a2b8')
    )

    db.session.add(t)
    db.session.commit()

    return success_response(t.to_dict(), message='Notification type created', http_code=201)


# =============================================================================
# Notifications CRUD
# =============================================================================

@notifications_bp.route('', methods=['GET'])
def list_notifications():
    """
    List all notifications with filtering and pagination.

    Query parameters:
    - page, per_page: Pagination
    - active: Filter by active status (default: true)
    - type_id: Filter by notification type ID
    - current: Filter to currently active notifications only
    - search: Search in notification text
    """
    page, per_page = get_pagination_params(request)

    query = Notification.query

    # Active filter
    if request.args.get('active', 'true').lower() != 'false':
        query = query.filter(Notification.isactive == True)

    # Type filter
    if type_id := request.args.get('type_id'):
        query = query.filter(Notification.notificationtypeid == int(type_id))

    # Current filter (active based on dates)
    if request.args.get('current', 'false').lower() == 'true':
        now = datetime.utcnow()
        query = query.filter(
            Notification.starttime <= now,
            db.or_(
                Notification.endtime.is_(None),
                Notification.endtime >= now
            )
        )

    # Search filter
    if search := request.args.get('search'):
        query = query.filter(
            Notification.notification.ilike(f'%{search}%')
        )

    # Sorting by start time (newest first)
    query = query.order_by(Notification.starttime.desc())

    items, total = paginate_query(query, page, per_page)
    data = [n.to_dict() for n in items]

    return paginated_response(data, page, per_page, total)


@notifications_bp.route('/<int:notification_id>', methods=['GET'])
def get_notification(notification_id: int):
    """Get a single notification."""
    n = Notification.query.get(notification_id)

    if not n:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Notification with ID {notification_id} not found',
            http_code=404
        )

    return success_response(n.to_dict())


@notifications_bp.route('', methods=['POST'])
@jwt_required()
def create_notification():
    """Create a new notification."""
    data = request.get_json()

    if not data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')

    # Validate required fields
    notification_text = data.get('notification') or data.get('message')
    if not notification_text:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'notification/message is required')

    # Parse dates
    starttime = datetime.utcnow()
    if data.get('starttime') or data.get('startdate'):
        try:
            date_str = data.get('starttime') or data.get('startdate')
            starttime = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
        except ValueError:
            return error_response(ErrorCodes.VALIDATION_ERROR, 'Invalid starttime format')

    endtime = None
    if data.get('endtime') or data.get('enddate'):
        try:
            date_str = data.get('endtime') or data.get('enddate')
            endtime = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
        except ValueError:
            return error_response(ErrorCodes.VALIDATION_ERROR, 'Invalid endtime format')

    n = Notification(
        notification=notification_text,
        notificationtypeid=data.get('notificationtypeid'),
        businessunitid=data.get('businessunitid'),
        appid=data.get('appid'),
        starttime=starttime,
        endtime=endtime,
        ticketnumber=data.get('ticketnumber'),
        link=data.get('link') or data.get('linkurl'),
        isactive=True,
        isshopfloor=data.get('isshopfloor', False),
        employeesso=data.get('employeesso'),
        employeename=data.get('employeename')
    )

    db.session.add(n)
    db.session.commit()

    return success_response(n.to_dict(), message='Notification created', http_code=201)


@notifications_bp.route('/<int:notification_id>', methods=['PUT'])
@jwt_required()
def update_notification(notification_id: int):
    """Update a notification."""
    n = Notification.query.get(notification_id)

    if not n:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Notification with ID {notification_id} not found',
            http_code=404
        )

    data = request.get_json()
    if not data:
        return error_response(ErrorCodes.VALIDATION_ERROR, 'No data provided')

    # Update text content
    if 'notification' in data or 'message' in data:
        n.notification = data.get('notification') or data.get('message')

    # Update simple fields
    if 'notificationtypeid' in data:
        n.notificationtypeid = data['notificationtypeid']
    if 'businessunitid' in data:
        n.businessunitid = data['businessunitid']
    if 'appid' in data:
        n.appid = data['appid']
    if 'ticketnumber' in data:
        n.ticketnumber = data['ticketnumber']
    if 'link' in data or 'linkurl' in data:
        n.link = data.get('link') or data.get('linkurl')
    if 'isactive' in data:
        n.isactive = data['isactive']
    if 'isshopfloor' in data:
        n.isshopfloor = data['isshopfloor']
    if 'employeesso' in data:
        n.employeesso = data['employeesso']
    if 'employeename' in data:
        n.employeename = data['employeename']

    # Parse and update dates
    if 'starttime' in data or 'startdate' in data:
        date_str = data.get('starttime') or data.get('startdate')
        if date_str:
            try:
                n.starttime = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
            except ValueError:
                return error_response(ErrorCodes.VALIDATION_ERROR, 'Invalid starttime format')
        else:
            n.starttime = datetime.utcnow()

    if 'endtime' in data or 'enddate' in data:
        date_str = data.get('endtime') or data.get('enddate')
        if date_str:
            try:
                n.endtime = datetime.fromisoformat(date_str.replace('Z', '+00:00'))
            except ValueError:
                return error_response(ErrorCodes.VALIDATION_ERROR, 'Invalid endtime format')
        else:
            n.endtime = None

    db.session.commit()
    return success_response(n.to_dict(), message='Notification updated')


@notifications_bp.route('/<int:notification_id>', methods=['DELETE'])
@jwt_required()
def delete_notification(notification_id: int):
    """Delete (soft delete) a notification."""
    n = Notification.query.get(notification_id)

    if not n:
        return error_response(
            ErrorCodes.NOT_FOUND,
            f'Notification with ID {notification_id} not found',
            http_code=404
        )

    n.isactive = False
    db.session.commit()

    return success_response(message='Notification deleted')


# =============================================================================
# Special Endpoints
# =============================================================================

@notifications_bp.route('/active', methods=['GET'])
def get_active_notifications():
    """
    Get currently active notifications for display.
    """
    now = datetime.utcnow()

    from datetime import timedelta
    lookahead = now + timedelta(days=10)

    notifications = Notification.query.filter(
        Notification.isactive == True,
        db.or_(
            Notification.starttime.is_(None),
            Notification.starttime <= lookahead
        ),
        db.or_(
            Notification.endtime.is_(None),
            Notification.endtime >= now
        )
    ).order_by(Notification.starttime.asc()).all()

    data = [n.to_dict() for n in notifications]

    return success_response({
        'notifications': data,
        'total': len(data)
    })


@notifications_bp.route('/calendar', methods=['GET'])
def get_calendar_events():
    """
    Get notifications in FullCalendar event format.

    Query parameters:
    - start: Start date (ISO format)
    - end: End date (ISO format)
    """
    query = Notification.query.filter(Notification.isactive == True)

    # Date range filter
    if start := request.args.get('start'):
        try:
            start_date = datetime.fromisoformat(start.replace('Z', '+00:00'))
            query = query.filter(
                db.or_(
                    Notification.endtime >= start_date,
                    Notification.endtime.is_(None)
                )
            )
        except ValueError:
            pass

    if end := request.args.get('end'):
        try:
            end_date = datetime.fromisoformat(end.replace('Z', '+00:00'))
            query = query.filter(Notification.starttime <= end_date)
        except ValueError:
            pass

    notifications = query.order_by(Notification.starttime).all()

    events = [n.to_calendar_event() for n in notifications]

    return success_response(events)


@notifications_bp.route('/dashboard/summary', methods=['GET'])
def dashboard_summary():
    """Get notifications dashboard summary."""
    now = datetime.utcnow()

    # Total active notifications
    total_active = Notification.query.filter(
        Notification.isactive == True,
        db.or_(
            Notification.starttime.is_(None),
            Notification.starttime <= now
        ),
        db.or_(
            Notification.endtime.is_(None),
            Notification.endtime >= now
        )
    ).count()

    # By type
    by_type = db.session.query(
        NotificationType.typename,
        NotificationType.typecolor,
        db.func.count(Notification.notificationid)
    ).join(Notification
    ).filter(
        Notification.isactive == True
    ).group_by(NotificationType.typename, NotificationType.typecolor
    ).all()

    return success_response({
        'active': total_active,
        'bytype': [{'type': t, 'color': c, 'count': n} for t, c, n in by_type]
    })


@notifications_bp.route('/employee/<sso>', methods=['GET'])
def get_employee_recognitions(sso):
    """
    Get recognitions for a specific employee by SSO.

    Returns all recognition-type notifications where the employee is mentioned.
    """
    if not sso or not sso.isdigit():
        return error_response(ErrorCodes.VALIDATION_ERROR, 'Valid SSO required')

    # Find recognition type(s)
    recognition_types = NotificationType.query.filter(
        db.or_(
            NotificationType.typecolor == 'recognition',
            NotificationType.typename.ilike('%recognition%')
        )
    ).all()

    recognition_type_ids = [rt.notificationtypeid for rt in recognition_types]

    # Find notifications where this employee is mentioned
    # Check both exact match and comma-separated list
    query = Notification.query.filter(
        Notification.isactive == True,
        db.or_(
            Notification.employeesso == sso,
            Notification.employeesso.like(f'{sso},%'),
            Notification.employeesso.like(f'%,{sso}'),
            Notification.employeesso.like(f'%,{sso},%')
        )
    )

    # Optionally filter to recognition types only
    if recognition_type_ids:
        query = query.filter(Notification.notificationtypeid.in_(recognition_type_ids))

    query = query.order_by(Notification.starttime.desc())

    notifications = query.all()
    data = [n.to_dict() for n in notifications]

    return success_response({
        'recognitions': data,
        'total': len(data)
    })


@notifications_bp.route('/shopfloor', methods=['GET'])
def get_shopfloor_notifications():
    """
    Get notifications for shopfloor TV dashboard.

    Returns current and upcoming notifications with isshopfloor=1.
    Splits multi-employee recognition into separate entries.

    Query parameters:
    - businessunit: Filter by business unit ID (null = all units)
    """
    from datetime import timedelta

    now = datetime.utcnow()
    business_unit = request.args.get('businessunit')

    # Base query for shopfloor notifications
    base_query = Notification.query.filter(Notification.isshopfloor == True)

    # Business unit filter
    if business_unit and business_unit.isdigit():
        # Specific BU: show that BU's notifications AND null (all units)
        base_query = base_query.filter(
            db.or_(
                Notification.businessunitid == int(business_unit),
                Notification.businessunitid.is_(None)
            )
        )
    else:
        # All units: only show notifications with NULL businessunitid
        base_query = base_query.filter(Notification.businessunitid.is_(None))

    # Current notifications (active now or ended within 30 minutes)
    thirty_min_ago = now - timedelta(minutes=30)
    current_query = base_query.filter(
        db.or_(
            # Active and currently showing
            db.and_(
                Notification.isactive == True,
                db.or_(Notification.starttime.is_(None), Notification.starttime <= now),
                db.or_(Notification.endtime.is_(None), Notification.endtime >= now)
            ),
            # Recently ended (within 30 min) - show as resolved
            db.and_(
                Notification.endtime.isnot(None),
                Notification.endtime >= thirty_min_ago,
                Notification.endtime < now
            )
        )
    ).order_by(Notification.notificationid.desc())

    current_notifications = current_query.all()

    # Upcoming notifications (starts within next 5 days)
    five_days = now + timedelta(days=5)
    upcoming_query = base_query.filter(
        Notification.isactive == True,
        Notification.starttime > now,
        Notification.starttime <= five_days
    ).order_by(Notification.starttime)

    upcoming_notifications = upcoming_query.all()

    def notification_to_shopfloor(n, employee_override=None):
        """Convert notification to shopfloor format."""
        is_resolved = n.endtime and n.endtime < now

        result = {
            'notificationid': n.notificationid,
            'notification': n.notification,
            'starttime': n.starttime.isoformat() if n.starttime else None,
            'endtime': n.endtime.isoformat() if n.endtime else None,
            'ticketnumber': n.ticketnumber,
            'link': n.link,
            'isactive': n.isactive,
            'isshopfloor': True,
            'resolved': is_resolved,
            'typename': n.notificationtype.typename if n.notificationtype else None,
            'typecolor': n.notificationtype.typecolor if n.notificationtype else None,
        }

        # Employee info
        if employee_override:
            result['employeesso'] = employee_override.get('sso')
            result['employeename'] = employee_override.get('name')
            result['employeepicture'] = employee_override.get('picture')
        else:
            result['employeesso'] = n.employeesso
            result['employeename'] = n.employeename
            result['employeepicture'] = None

            # Try to get picture from wjf_employees
            if n.employeesso and n.employeesso.isdigit():
                try:
                    import pymysql
                    conn = pymysql.connect(
                        host='localhost', user='root', password='rootpassword',
                        database='wjf_employees', cursorclass=pymysql.cursors.DictCursor
                    )
                    with conn.cursor() as cur:
                        cur.execute('SELECT Picture FROM employees WHERE SSO = %s', (int(n.employeesso),))
                        emp = cur.fetchone()
                        if emp and emp.get('Picture'):
                            result['employeepicture'] = emp['Picture']
                    conn.close()
                except Exception:
                    pass

        return result

    # Process current notifications (split multi-employee recognition)
    current_data = []
    for n in current_notifications:
        is_recognition = n.notificationtype and n.notificationtype.typecolor == 'recognition'

        if is_recognition and n.employeesso and ',' in n.employeesso:
            # Split into individual cards for each employee
            ssos = [s.strip() for s in n.employeesso.split(',')]
            names = n.employeename.split(', ') if n.employeename else []

            for i, sso in enumerate(ssos):
                name = names[i] if i < len(names) else sso

                # Look up picture
                picture = None
                if sso.isdigit():
                    try:
                        import pymysql
                        conn = pymysql.connect(
                            host='localhost', user='root', password='rootpassword',
                            database='wjf_employees', cursorclass=pymysql.cursors.DictCursor
                        )
                        with conn.cursor() as cur:
                            cur.execute('SELECT Picture FROM employees WHERE SSO = %s', (int(sso),))
                            emp = cur.fetchone()
                            if emp:
                                picture = emp.get('Picture')
                        conn.close()
                    except Exception:
                        pass

                current_data.append(notification_to_shopfloor(n, {
                    'sso': sso,
                    'name': name,
                    'picture': picture
                }))
        else:
            current_data.append(notification_to_shopfloor(n))

    # Process upcoming notifications
    upcoming_data = []
    for n in upcoming_notifications:
        is_recognition = n.notificationtype and n.notificationtype.typecolor == 'recognition'

        if is_recognition and n.employeesso and ',' in n.employeesso:
            ssos = [s.strip() for s in n.employeesso.split(',')]
            names = n.employeename.split(', ') if n.employeename else []

            for i, sso in enumerate(ssos):
                name = names[i] if i < len(names) else sso
                picture = None
                if sso.isdigit():
                    try:
                        import pymysql
                        conn = pymysql.connect(
                            host='localhost', user='root', password='rootpassword',
                            database='wjf_employees', cursorclass=pymysql.cursors.DictCursor
                        )
                        with conn.cursor() as cur:
                            cur.execute('SELECT Picture FROM employees WHERE SSO = %s', (int(sso),))
                            emp = cur.fetchone()
                            if emp:
                                picture = emp.get('Picture')
                        conn.close()
                    except Exception:
                        pass

                upcoming_data.append(notification_to_shopfloor(n, {
                    'sso': sso,
                    'name': name,
                    'picture': picture
                }))
        else:
            upcoming_data.append(notification_to_shopfloor(n))

    return success_response({
        'timestamp': now.isoformat(),
        'current': current_data,
        'upcoming': upcoming_data
    })
