from flask import Flask, render_template, request, jsonify, send_file, flash, redirect, url_for
from database import init_db, add_camera, get_cameras, delete_camera, add_recording, get_recordings
from apscheduler.schedulers.background import BackgroundScheduler
from datetime import datetime, timedelta
import requests
from requests.auth import HTTPBasicAuth
import os
import logging

app = Flask(__name__)
app.secret_key = 'your-secret-key-here'  # Change this!

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Scheduler for auto-stopping recordings
scheduler = BackgroundScheduler()
scheduler.start()

# Track active recordings: {recording_id: {'camera_id': id, 'stop_time': datetime}}
active_recordings = {}

RECORDINGS_DIR = 'recordings'
os.makedirs(RECORDINGS_DIR, exist_ok=True)


def make_camera_request(camera, endpoint, params=None, stream=False):
    """Make authenticated request to Axis camera API"""
    url = f"http://{camera['ip']}:{camera['port']}{endpoint}"
    try:
        response = requests.get(
            url,
            auth=HTTPBasicAuth(camera['username'], camera['password']),
            params=params,
            timeout=30,
            stream=stream
        )
        response.raise_for_status()
        return response
    except requests.RequestException as e:
        logger.error(f"Camera request failed: {e}")
        raise


def start_recording_on_camera(camera):
    """Start recording on camera and return recording ID"""
    response = make_camera_request(camera, '/axis-cgi/record/record.cgi', 
                                    {'diskid': 'SD_DISK'})
    # The response typically contains the recording ID
    # Parse it from the response text
    return response.text


def stop_recording_on_camera(camera, recording_id):
    """Stop recording on camera"""
    response = make_camera_request(camera, '/axis-cgi/record/stop.cgi',
                                    {'recordingid': recording_id})
    return response.text


def export_recording(camera, recording_id, output_path):
    """Download recording from camera"""
    response = make_camera_request(
        camera, 
        '/axis-cgi/record/export/exportrecording.cgi',
        {'recordingid': recording_id, 'format': 'mp4'},
        stream=True
    )
    
    with open(output_path, 'wb') as f:
        for chunk in response.iter_content(chunk_size=8192):
            f.write(chunk)
    
    return output_path


def auto_stop_recording(recording_db_id, camera_id, recording_id):
    """Scheduled job to stop recording and export"""
    from database import get_camera_by_id, update_recording_status
    
    camera = get_camera_by_id(camera_id)
    if not camera:
        logger.error(f"Camera {camera_id} not found for stopping recording")
        return
    
    try:
        # Stop the recording
        stop_recording_on_camera(camera, recording_id)
        logger.info(f"Stopped recording {recording_id} on camera {camera['ip']}")
        
        # Export the video
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f"camera_{camera_id}_{timestamp}.mp4"
        filepath = os.path.join(RECORDINGS_DIR, filename)
        
        export_recording(camera, recording_id, filepath)
        logger.info(f"Exported recording to {filepath}")
        
        # Update database
        update_recording_status(recording_db_id, 'completed', filepath)
        
    except Exception as e:
        logger.error(f"Failed to stop/export recording: {e}")
        update_recording_status(recording_db_id, 'failed', None)


@app.route('/')
def index():
    cameras = get_cameras()
    recordings = get_recordings()
    return render_template('index.html', cameras=cameras, recordings=recordings)


@app.route('/cameras/add', methods=['POST'])
def add_camera_route():
    ip = request.form.get('ip')
    port = request.form.get('port', 80)
    username = request.form.get('username')
    password = request.form.get('password')
    name = request.form.get('name', f'Camera {ip}')
    
    if not all([ip, username, password]):
        flash('IP, username, and password are required', 'error')
        return redirect(url_for('index'))
    
    try:
        add_camera(name, ip, port, username, password)
        flash('Camera added successfully', 'success')
    except Exception as e:
        flash(f'Error adding camera: {e}', 'error')
    
    return redirect(url_for('index'))


@app.route('/cameras/delete/<int:camera_id>', methods=['POST'])
def delete_camera_route(camera_id):
    try:
        delete_camera(camera_id)
        flash('Camera deleted successfully', 'success')
    except Exception as e:
        flash(f'Error deleting camera: {e}', 'error')
    
    return redirect(url_for('index'))


@app.route('/cameras/test/<int:camera_id>')
def test_camera_route(camera_id):
    """Test connection to camera"""
    from database import get_camera_by_id
    camera = get_camera_by_id(camera_id)
    
    if not camera:
        return jsonify({'success': False, 'message': 'Camera not found'})
    
    try:
        response = make_camera_request(camera, '/axis-cgi/record/list.cgi')
        return jsonify({'success': True, 'message': 'Connection successful', 'response': response.text[:500]})
    except Exception as e:
        return jsonify({'success': False, 'message': str(e)})


@app.route('/recordings/start/<int:camera_id>', methods=['POST'])
def start_recording_route(camera_id):
    from database import get_camera_by_id
    
    camera = get_camera_by_id(camera_id)
    if not camera:
        flash('Camera not found', 'error')
        return redirect(url_for('index'))
    
    duration_minutes = int(request.form.get('duration', 5))
    
    try:
        # Start recording
        response = start_recording_on_camera(camera)
        logger.info(f"Start recording response: {response}")
        
        # Try to extract recording ID from response
        # Axis typically returns something like "recordingid=12345"
        recording_id = None
        if 'recordingid=' in response:
            recording_id = response.split('recordingid=')[1].split()[0].strip()
        
        if not recording_id:
            # If we can't get ID immediately, we'll need to poll list.cgi
            flash('Recording started (ID pending)', 'warning')
            return redirect(url_for('index'))
        
        # Schedule auto-stop
        stop_time = datetime.now() + timedelta(minutes=duration_minutes)
        
        # Add to database
        recording_db_id = add_recording(
            camera_id=camera_id,
            recording_id=recording_id,
            duration_minutes=duration_minutes,
            scheduled_stop=stop_time
        )
        
        # Schedule the stop job
        scheduler.add_job(
            auto_stop_recording,
            'date',
            run_date=stop_time,
            args=[recording_db_id, camera_id, recording_id],
            id=f'stop_{recording_db_id}'
        )
        
        flash(f'Recording started! Will stop in {duration_minutes} minutes', 'success')
        
    except Exception as e:
        flash(f'Error starting recording: {e}', 'error')
        logger.error(f"Start recording error: {e}")
    
    return redirect(url_for('index'))


@app.route('/recordings/stop/<int:recording_id>', methods=['POST'])
def stop_recording_route(recording_id):
    from database import get_recording_by_id, get_camera_by_id
    
    recording = get_recording_by_id(recording_id)
    if not recording or not recording['recording_id']:
        flash('Recording not found', 'error')
        return redirect(url_for('index'))
    
    camera = get_camera_by_id(recording['camera_id'])
    
    try:
        stop_recording_on_camera(camera, recording['recording_id'])
        
        # Cancel scheduled job if exists
        try:
            scheduler.remove_job(f'stop_{recording_id}')
        except:
            pass
        
        # Export immediately
        timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
        filename = f"camera_{recording['camera_id']}_{timestamp}.mp4"
        filepath = os.path.join(RECORDINGS_DIR, filename)
        
        export_recording(camera, recording['recording_id'], filepath)
        
        from database import update_recording_status
        update_recording_status(recording_id, 'completed', filepath)
        
        flash('Recording stopped and exported', 'success')
        
    except Exception as e:
        flash(f'Error stopping recording: {e}', 'error')
        logger.error(f"Stop recording error: {e}")
    
    return redirect(url_for('index'))


@app.route('/recordings/download/<int:recording_id>')
def download_recording_route(recording_id):
    from database import get_recording_by_id
    
    recording = get_recording_by_id(recording_id)
    if not recording or not recording['file_path']:
        flash('Recording file not found', 'error')
        return redirect(url_for('index'))
    
    if not os.path.exists(recording['file_path']):
        flash('Recording file not found on disk', 'error')
        return redirect(url_for('index'))
    
    return send_file(
        recording['file_path'],
        as_attachment=True,
        download_name=os.path.basename(recording['file_path'])
    )


@app.route('/recordings/delete/<int:recording_id>', methods=['POST'])
def delete_recording_route(recording_id):
    from database import delete_recording
    
    recording = get_recordings()
    rec = next((r for r in recording if r['id'] == recording_id), None)
    
    if rec and rec.get('file_path') and os.path.exists(rec['file_path']):
        os.remove(rec['file_path'])
    
    delete_recording(recording_id)
    flash('Recording deleted', 'success')
    return redirect(url_for('index'))


if __name__ == '__main__':
    init_db()
    app.run(debug=True, host='0.0.0.0', port=5800)
