"""
Calendar Routes for Scheduling
Handles availability calendar and views
"""

from flask import render_template, request, jsonify, redirect, url_for, session
from flask_login import login_required, current_user
from datetime import datetime, date, timedelta
from . import scheduling_bp
from app.extensions import db
from app.models.availability import Availability, AvailabilityStatus, WorkerSchedulePreferences
from app.models.booking import Booking, BookingStatus
from app.models.time_tracking import TimeEntry, Shift
import json
import os


@scheduling_bp.route('/google/auth', methods=['GET'])
def google_auth():
    """Initiate Google Calendar OAuth2 flow"""
    from app.services.calendar_sync_service import CalendarSyncService
    
    try:
        # Use test user_id=1 for now (TODO: use current_user.id when auth is enabled)
        user_id = current_user.id if hasattr(current_user, 'id') and current_user.is_authenticated else 1
        
        auth_url = CalendarSyncService.get_google_auth_url(user_id)
        return redirect(auth_url)
    except Exception as e:
        return jsonify({'error': f'Failed to initiate Google OAuth: {str(e)}'}), 500


@scheduling_bp.route('/google/callback', methods=['GET'])
def google_callback():
    """Handle Google Calendar OAuth2 callback"""
    from app.services.calendar_sync_service import CalendarSyncService
    
    code = request.args.get('code')
    state = request.args.get('state')  # Contains user_id
    
    if not code:
        return jsonify({'error': 'No authorization code received'}), 400
    
    try:
        result = CalendarSyncService.handle_google_callback(code, state)
        
        if result['success']:
            # Redirect to debug list endpoint
            return redirect(url_for('scheduling.google_debug_list'))
        else:
            return jsonify(result), 400
            
    except Exception as e:
        return jsonify({'error': f'Failed to handle Google callback: {str(e)}'}), 500


@scheduling_bp.route('/google/debug/list', methods=['GET'])
def google_debug_list():
    """Debug endpoint to list next 10 events from primary calendar"""
    from app.services.calendar_sync_service import CalendarSyncService
    from datetime import datetime, timedelta
    
    try:
        # Use test user_id=1 for now (TODO: use current_user.id when auth is enabled)
        user_id = current_user.id if hasattr(current_user, 'id') and current_user.is_authenticated else 1
        
        # Get events for next 30 days
        start_date = datetime.now()
        end_date = start_date + timedelta(days=30)
        
        events = CalendarSyncService.import_from_google(user_id, start_date, end_date)
        
        return jsonify({
            'success': True,
            'user_id': user_id,
            'events_count': len(events),
            'events': events[:10]  # Limit to 10 events
        })
        
    except Exception as e:
        return jsonify({
            'error': f'Failed to list events: {str(e)}',
            'success': False
        }), 500


@scheduling_bp.route('/google/disconnect', methods=['POST'])
@login_required
def google_disconnect():
    """Disconnect Google Calendar and revoke access"""
    from app.services.calendar_sync_service import CalendarSyncService
    
    try:
        success = CalendarSyncService.disconnect_google_calendar(current_user.id)
        
        if success:
            return jsonify({
                'success': True,
                'message': 'Google Calendar disconnected successfully'
            })
        else:
            return jsonify({
                'success': False,
                'error': 'Failed to disconnect Google Calendar'
            }), 400
            
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'Error disconnecting Google Calendar: {str(e)}'
        }), 500


@scheduling_bp.route('/outlook/disconnect', methods=['POST'])
@login_required
def outlook_disconnect():
    """Disconnect Outlook Calendar"""
    from app.services.calendar_sync_service import CalendarSyncService
    
    try:
        success = CalendarSyncService.disconnect_outlook_calendar(current_user.id)
        
        if success:
            return jsonify({
                'success': True,
                'message': 'Outlook Calendar disconnected successfully'
            })
        else:
            return jsonify({
                'success': False,
                'error': 'Failed to disconnect Outlook Calendar'
            }), 400
            
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'Error disconnecting Outlook Calendar: {str(e)}'
        }), 500


@scheduling_bp.route('/sync-status', methods=['GET'])
@login_required
def get_sync_status():
    """Get calendar sync status for current user"""
    try:
        from app.models.user import User
        user = User.query.get(current_user.id)
        
        if not user:
            return jsonify({'error': 'User not found'}), 404
        
        # Check which calendars are connected
        google_connected = False
        outlook_connected = False
        
        if user.calendar_sync_data_encrypted:
            from app.utils.encryption import token_encryptor
            token_data = token_encryptor.decrypt_token(user.calendar_sync_data_encrypted)
            if token_data:
                google_connected = 'google' in token_data
                outlook_connected = 'microsoft' in token_data
        
        return jsonify({
            'success': True,
            'sync_enabled': user.calendar_sync_enabled,
            'google_connected': google_connected,
            'outlook_connected': outlook_connected,
            'last_sync': user.calendar_last_sync.isoformat() if user.calendar_last_sync else None
        })
        
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'Error getting sync status: {str(e)}'
        }), 500


@scheduling_bp.route('/calendar', methods=['GET'])
@login_required
def calendar_view():
    """Render the calendar view"""
    return render_template('scheduling/calendar.html')


@scheduling_bp.route('/api/availability', methods=['GET'])
@login_required
def get_availability():
    """Get availability for a date range"""
    start_date = request.args.get('start')
    end_date = request.args.get('end')
    worker_id = request.args.get('worker_id', current_user.id, type=int)
    
    if not start_date or not end_date:
        return jsonify({'error': 'Start and end dates required'}), 400
    
    try:
        start = datetime.strptime(start_date, '%Y-%m-%d').date()
        end = datetime.strptime(end_date, '%Y-%m-%d').date()
    except ValueError:
        return jsonify({'error': 'Invalid date format'}), 400
    
    # Get availability slots
    availability = Availability.query.filter(
        Availability.worker_id == worker_id,
        Availability.date >= start,
        Availability.date <= end
    ).all()
    
    # Get bookings
    bookings = Booking.query.filter(
        Booking.worker_id == worker_id,
        Booking.booking_date >= start,
        Booking.booking_date <= end,
        Booking.status.in_([BookingStatus.CONFIRMED, BookingStatus.IN_PROGRESS])
    ).all()
    
    # Get shifts
    shifts = Shift.query.filter(
        Shift.worker_id == worker_id,
        Shift.shift_date >= start,
        Shift.shift_date <= end
    ).all()
    
    events = []
    
    # Add availability slots as events
    for slot in availability:
        color = '#28a745' if slot.status == AvailabilityStatus.AVAILABLE else '#dc3545'
        events.append({
            'id': f'availability_{slot.id}',
            'title': f'Available ({slot.current_bookings}/{slot.max_bookings})' if slot.status == AvailabilityStatus.AVAILABLE else slot.status.title(),
            'start': f'{slot.date}T{slot.start_time}',
            'end': f'{slot.date}T{slot.end_time}',
            'color': color,
            'type': 'availability',
            'data': slot.to_dict()
        })
    
    # Add bookings as events
    for booking in bookings:
        events.append({
            'id': f'booking_{booking.id}',
            'title': f'{booking.service_type} - {booking.client.first_name}',
            'start': f'{booking.booking_date}T{booking.start_time}',
            'end': f'{booking.booking_date}T{booking.end_time}',
            'color': '#007bff',
            'type': 'booking',
            'data': booking.to_dict()
        })
    
    # Add shifts as events
    for shift in shifts:
        events.append({
            'id': f'shift_{shift.id}',
            'title': f'{shift.shift_name or shift.shift_type or "Shift"}',
            'start': f'{shift.shift_date}T{shift.start_time}',
            'end': f'{shift.shift_date}T{shift.end_time}',
            'color': '#ffc107',
            'type': 'shift',
            'data': shift.to_dict()
        })
    
    return jsonify({
        'success': True,
        'events': events
    })


@scheduling_bp.route('/api/availability', methods=['POST'])
@login_required
def create_availability():
    """Create or update availability"""
    data = request.get_json()
    
    if not data:
        return jsonify({'error': 'No data provided'}), 400
    
    required_fields = ['date', 'start_time', 'end_time']
    for field in required_fields:
        if field not in data:
            return jsonify({'error': f'{field} is required'}), 400
    
    try:
        # Parse date and times
        availability_date = datetime.strptime(data['date'], '%Y-%m-%d').date()
        start_time = datetime.strptime(data['start_time'], '%H:%M').time()
        end_time = datetime.strptime(data['end_time'], '%H:%M').time()
        
        # Check if availability already exists
        existing = Availability.query.filter(
            Availability.worker_id == current_user.id,
            Availability.date == availability_date,
            Availability.start_time == start_time,
            Availability.end_time == end_time
        ).first()
        
        if existing:
            # Update existing
            existing.status = data.get('status', AvailabilityStatus.AVAILABLE)
            existing.max_bookings = data.get('max_bookings', 1)
            existing.buffer_time = data.get('buffer_time', 30)
            existing.notes = data.get('notes')
            availability = existing
        else:
            # Create new
            availability = Availability(
                worker_id=current_user.id,
                date=availability_date,
                start_time=start_time,
                end_time=end_time,
                status=data.get('status', AvailabilityStatus.AVAILABLE),
                is_recurring=data.get('is_recurring', False),
                recurrence_pattern=json.dumps(data['recurrence_pattern']) if data.get('recurrence_pattern') else None,
                max_bookings=data.get('max_bookings', 1),
                buffer_time=data.get('buffer_time', 30),
                notes=data.get('notes')
            )
            db.session.add(availability)
        
        # Handle recurring availability
        if availability.is_recurring and data.get('recurrence_pattern'):
            create_recurring_availability(availability, data['recurrence_pattern'])
        
        db.session.commit()
        
        return jsonify({
            'success': True,
            'availability': availability.to_dict()
        })
        
    except ValueError as e:
        return jsonify({'error': f'Invalid date/time format: {str(e)}'}), 400
    except Exception as e:
        db.session.rollback()
        return jsonify({'error': str(e)}), 500


@scheduling_bp.route('/api/availability/<int:availability_id>', methods=['DELETE'])
@login_required
def delete_availability(availability_id):
    """Delete availability slot"""
    availability = Availability.query.get_or_404(availability_id)
    
    # Check ownership
    if availability.worker_id != current_user.id:
        return jsonify({'error': 'Unauthorized'}), 403
    
    # Check if there are bookings
    if availability.current_bookings > 0:
        return jsonify({'error': 'Cannot delete availability with existing bookings'}), 400
    
    db.session.delete(availability)
    db.session.commit()
    
    return jsonify({'success': True, 'message': 'Availability deleted'})


@scheduling_bp.route('/api/schedule-preferences', methods=['GET'])
@login_required
def get_schedule_preferences():
    """Get worker's schedule preferences"""
    prefs = WorkerSchedulePreferences.query.filter_by(worker_id=current_user.id).first()
    
    if not prefs:
        # Create default preferences
        prefs = WorkerSchedulePreferences(worker_id=current_user.id)
        db.session.add(prefs)
        db.session.commit()
    
    return jsonify({
        'success': True,
        'preferences': prefs.to_dict()
    })


@scheduling_bp.route('/api/schedule-preferences', methods=['POST'])
@login_required
def update_schedule_preferences():
    """Update worker's schedule preferences"""
    data = request.get_json()
    
    prefs = WorkerSchedulePreferences.query.filter_by(worker_id=current_user.id).first()
    if not prefs:
        prefs = WorkerSchedulePreferences(worker_id=current_user.id)
        db.session.add(prefs)
    
    # Update preferences
    if 'default_start_time' in data:
        prefs.default_start_time = datetime.strptime(data['default_start_time'], '%H:%M').time()
    if 'default_end_time' in data:
        prefs.default_end_time = datetime.strptime(data['default_end_time'], '%H:%M').time()
    if 'working_days' in data:
        prefs.working_days = json.dumps(data['working_days'])
    if 'default_buffer_time' in data:
        prefs.default_buffer_time = data['default_buffer_time']
    if 'travel_time_buffer' in data:
        prefs.travel_time_buffer = data['travel_time_buffer']
    if 'min_advance_booking' in data:
        prefs.min_advance_booking = data['min_advance_booking']
    if 'max_advance_booking' in data:
        prefs.max_advance_booking = data['max_advance_booking']
    if 'reminder_time' in data:
        prefs.reminder_time = data['reminder_time']
    if 'reminder_method' in data:
        prefs.reminder_method = data['reminder_method']
    
    db.session.commit()
    
    return jsonify({
        'success': True,
        'preferences': prefs.to_dict()
    })


def create_recurring_availability(template, pattern):
    """Create recurring availability slots based on pattern"""
    from datetime import date, timedelta
    import calendar
    
    if pattern['type'] == 'weekly':
        # Create weekly recurring slots
        end_date = datetime.strptime(pattern.get('end_date', ''), '%Y-%m-%d').date() if pattern.get('end_date') else None
        current_date = template.date + timedelta(days=7)
        
        while current_date <= (end_date or (template.date + timedelta(days=365))):
            # Check if this slot already exists
            existing = Availability.query.filter(
                Availability.worker_id == template.worker_id,
                Availability.date == current_date,
                Availability.start_time == template.start_time,
                Availability.end_time == template.end_time
            ).first()
            
            if not existing:
                new_slot = Availability(
                    worker_id=template.worker_id,
                    date=current_date,
                    start_time=template.start_time,
                    end_time=template.end_time,
                    status=template.status,
                    is_recurring=True,
                    recurrence_pattern=template.recurrence_pattern,
                    max_bookings=template.max_bookings,
                    buffer_time=template.buffer_time,
                    notes=template.notes
                )
                db.session.add(new_slot)
            
            current_date += timedelta(days=7)
    
    elif pattern['type'] == 'daily':
        # Create daily recurring slots
        end_date = datetime.strptime(pattern.get('end_date', ''), '%Y-%m-%d').date() if pattern.get('end_date') else None
        current_date = template.date + timedelta(days=1)
        
        while current_date <= (end_date or (template.date + timedelta(days=30))):
            # Check if this slot already exists
            existing = Availability.query.filter(
                Availability.worker_id == template.worker_id,
                Availability.date == current_date,
                Availability.start_time == template.start_time,
                Availability.end_time == template.end_time
            ).first()
            
            if not existing:
                new_slot = Availability(
                    worker_id=template.worker_id,
                    date=current_date,
                    start_time=template.start_time,
                    end_time=template.end_time,
                    status=template.status,
                    is_recurring=True,
                    recurrence_pattern=template.recurrence_pattern,
                    max_bookings=template.max_bookings,
                    buffer_time=template.buffer_time,
                    notes=template.notes
                )
                db.session.add(new_slot)
            
            current_date += timedelta(days=1)


@scheduling_bp.route('/api/time-tracking/clock-in', methods=['POST'])
@login_required
def clock_in():
    """Clock in for work"""
    data = request.get_json()
    
    # Check if already clocked in
    active_entry = TimeEntry.query.filter(
        TimeEntry.worker_id == current_user.id,
        TimeEntry.clock_out.is_(None)
    ).first()
    
    if active_entry:
        return jsonify({'error': 'Already clocked in'}), 400
    
    entry = TimeEntry(
        worker_id=current_user.id,
        job_id=data.get('job_id'),
        booking_id=data.get('booking_id'),
        contract_id=data.get('contract_id'),
        work_date=date.today(),
        location=data.get('location'),
        description=data.get('description')
    )
    entry.clock_in_now()
    
    db.session.add(entry)
    db.session.commit()
    
    return jsonify({
        'success': True,
        'time_entry': entry.to_dict()
    })


@scheduling_bp.route('/api/time-tracking/clock-out', methods=['POST'])
@login_required
def clock_out():
    """Clock out from work"""
    # Find active entry
    entry = TimeEntry.query.filter(
        TimeEntry.worker_id == current_user.id,
        TimeEntry.clock_out.is_(None)
    ).first()
    
    if not entry:
        return jsonify({'error': 'Not clocked in'}), 400
    
    entry.clock_out_now()
    db.session.commit()
    
    return jsonify({
        'success': True,
        'time_entry': entry.to_dict()
    })
