import re
import json
import uuid
from pathlib import Path
from werkzeug.utils import secure_filename
from werkzeug.security import generate_password_hash, check_password_hash
from flask import Blueprint, jsonify, request, abort, send_file, render_template
import db
import extensions
from auth import login_required
from utils.system import local_ip

bp = Blueprint('livechat', __name__)

_HEX_COLOR = re.compile(r'^#[0-9a-fA-F]{6}$')

CHAT_USERS_FILE = Path(__file__).parent.parent.parent / 'chat_users.json'
CHAT_AVATARS_DIR = Path(__file__).parent.parent.parent / 'static' / 'chat_avatars'
CHAT_IMAGES_DIR  = Path(__file__).parent.parent.parent / 'static' / 'chat_images'

CHAT_AVATARS_DIR.mkdir(exist_ok=True)
CHAT_IMAGES_DIR.mkdir(exist_ok=True)

_AVATAR_EXTS   = ['.jpg', '.jpeg', '.png', '.webp']
_CHAT_IMG_EXTS = {'.jpg', '.jpeg', '.png', '.gif', '.webp'}

_CHAT_COLORS = [
    '#f87171', '#fb923c', '#fbbf24', '#a3e635',
    '#34d399', '#38bdf8', '#818cf8', '#e879f9',
    '#f472b6', '#94a3b8',
]

# Shared in-memory token store: token -> {username, emoji, color, avatar_url}
# Imported by events.py so both modules share the same dict.
chat_tokens = {}


def _load_chat_users():
    try:
        if CHAT_USERS_FILE.exists():
            return json.loads(CHAT_USERS_FILE.read_text())
    except Exception:
        pass
    return {}


def _save_chat_users(users):
    CHAT_USERS_FILE.write_text(json.dumps(users, indent=2))


def get_avatar_url(username):
    safe = re.sub(r'[^a-zA-Z0-9_\-]', '_', username)
    for ext in _AVATAR_EXTS:
        if (CHAT_AVATARS_DIR / (safe + ext)).exists():
            return f'/api/chat/avatar/{username}'
    return None


def _restore_chat_tokens():
    users = _load_chat_users()
    for username, u in users.items():
        token = u.get('token')
        if token:
            chat_tokens[token] = {
                'username':   username,
                'emoji':      u.get('emoji', '😀'),
                'color':      u.get('color', '#94a3b8'),
                'avatar_url': get_avatar_url(username),
            }


_restore_chat_tokens()


# --- Page routes ---

@bp.route('/chat-display')
def chat_display():
    return render_template('chat_display.html', local_ip=local_ip())


@bp.route('/chat-mobile')
def chat_mobile():
    return render_template('chat_mobile.html')


@bp.route('/api/chat-qr')
def chat_qr():
    try:
        import qrcode as _qr
        import io as _io
        url = f'http://{local_ip()}:5000/chat-mobile'
        qr = _qr.QRCode(box_size=20, border=2)
        qr.add_data(url)
        qr.make(fit=True)
        img = qr.make_image()
        buf = _io.BytesIO()
        img.save(buf, format='PNG')
        buf.seek(0)
        return send_file(buf, mimetype='image/png', max_age=30)
    except ImportError:
        abort(501)


# --- Auth routes ---

@bp.route('/api/chat/register', methods=['POST'])
def chat_register():
    data     = request.get_json(silent=True) or {}
    username = str(data.get('username', '')).strip()[:32]
    password = str(data.get('password', '')).strip()
    emoji    = str(data.get('emoji', '😀')).strip()[:4]
    if not username or not password:
        return jsonify({'error': 'Användarnamn och lösenord krävs'}), 400
    users = _load_chat_users()
    if username.lower() in {k.lower() for k in users}:
        return jsonify({'error': 'Användarnamnet är redan taget'}), 409
    color = _CHAT_COLORS[len(users) % len(_CHAT_COLORS)]
    token = str(uuid.uuid4())
    users[username] = {
        'password_hash': generate_password_hash(password),
        'emoji':         emoji,
        'color':         color,
        'token':         token,
    }
    _save_chat_users(users)
    chat_tokens[token] = {'username': username, 'emoji': emoji, 'color': color, 'avatar_url': None}
    return jsonify({'token': token, 'username': username, 'emoji': emoji, 'color': color, 'avatar_url': None})


@bp.route('/api/chat/login', methods=['POST'])
def chat_login():
    data     = request.get_json(silent=True) or {}
    username = str(data.get('username', '')).strip()
    password = str(data.get('password', '')).strip()
    if not username or not password:
        return jsonify({'error': 'Fyll i användarnamn och lösenord'}), 400
    users = _load_chat_users()
    key   = next((k for k in users if k.lower() == username.lower()), None)
    if not key or not check_password_hash(users[key]['password_hash'], password):
        return jsonify({'error': 'Fel användarnamn eller lösenord'}), 401
    u          = users[key]
    avatar_url = get_avatar_url(key)
    token      = str(uuid.uuid4())
    chat_tokens[token] = {'username': key, 'emoji': u['emoji'], 'color': u['color'], 'avatar_url': avatar_url}
    users[key]['token'] = token
    _save_chat_users(users)
    return jsonify({'token': token, 'username': key, 'emoji': u['emoji'], 'color': u['color'], 'avatar_url': avatar_url})


@bp.route('/api/chat/validate', methods=['POST'])
def chat_validate():
    data  = request.get_json(silent=True) or {}
    token = str(data.get('token', ''))
    user  = chat_tokens.get(token)
    if not user:
        return jsonify({'error': 'Ogiltig token'}), 401
    if not user.get('avatar_url'):
        user['avatar_url'] = get_avatar_url(user['username'])
    return jsonify({'username': user['username'], 'emoji': user['emoji'], 'color': user['color'], 'avatar_url': user.get('avatar_url')})


# --- Avatar & image routes ---

@bp.route('/api/chat/avatar/<username>')
def serve_chat_avatar(username):
    safe = re.sub(r'[^a-zA-Z0-9_\-]', '_', username)
    for ext in _AVATAR_EXTS:
        p = CHAT_AVATARS_DIR / (safe + ext)
        if p.exists():
            return send_file(p)
    abort(404)


@bp.route('/api/chat/avatar', methods=['POST'])
def upload_chat_avatar():
    token     = request.form.get('token', '')
    user_info = chat_tokens.get(token)
    if not user_info:
        return jsonify({'error': 'Ogiltig token'}), 401
    f = request.files.get('avatar')
    if not f or not f.filename:
        return jsonify({'error': 'Ingen fil'}), 400
    ext = Path(secure_filename(f.filename)).suffix.lower()
    if ext not in _AVATAR_EXTS:
        return jsonify({'error': 'Använd jpg, png eller webp'}), 400
    username = user_info['username']
    safe     = re.sub(r'[^a-zA-Z0-9_\-]', '_', username)
    for old_ext in _AVATAR_EXTS:
        old = CHAT_AVATARS_DIR / (safe + old_ext)
        if old.exists():
            old.unlink()
    dest = CHAT_AVATARS_DIR / (safe + ext)
    f.save(str(dest))
    avatar_url = f'/api/chat/avatar/{username}'
    user_info['avatar_url'] = avatar_url
    users = _load_chat_users()
    if username in users:
        users[username]['avatar_url'] = avatar_url
        _save_chat_users(users)
    return jsonify({'avatar_url': avatar_url})


@bp.route('/api/chat/image', methods=['POST'])
def upload_chat_image():
    token     = request.form.get('token', '')
    user_info = chat_tokens.get(token)
    if not user_info:
        return jsonify({'error': 'Ogiltig token'}), 401
    f = request.files.get('image')
    if not f or not f.filename:
        return jsonify({'error': 'Ingen fil'}), 400
    ext = Path(secure_filename(f.filename)).suffix.lower()
    if ext not in _CHAT_IMG_EXTS:
        return jsonify({'error': 'Använd jpg, png, gif eller webp'}), 400
    filename = uuid.uuid4().hex + ext
    f.save(str(CHAT_IMAGES_DIR / filename))
    return jsonify({'url': f'/static/chat_images/{filename}'})


# --- Chat overlay settings (YouTube chat + kiosk chat display) ---

@bp.route('/api/chat', methods=['GET'])
def get_chat():
    state = db.get_state()
    return jsonify({
        'kiosk_enabled':   state.get('kiosk_chat_enabled',   '0') == '1',
        'kiosk_position':  state.get('kiosk_chat_position',  'right'),
        'kiosk_width_pct': int(state.get('kiosk_chat_width', '30')),
        'kiosk_height':    int(state.get('kiosk_chat_height','80')),
    })


@bp.route('/api/chat', methods=['POST'])
@login_required
def set_chat():
    data = request.get_json()
    if not data:
        abort(400)
    kiosk_enabled   = bool(data.get('kiosk_enabled', False))
    kiosk_position  = 'left' if data.get('kiosk_position') == 'left' else 'right'
    kiosk_width_pct = max(10, min(60,  int(data.get('kiosk_width_pct', 30))))
    kiosk_height    = max(30, min(100, int(data.get('kiosk_height',    80))))
    db.set_state('kiosk_chat_enabled',  '1' if kiosk_enabled else '0')
    db.set_state('kiosk_chat_position', kiosk_position)
    db.set_state('kiosk_chat_width',    str(kiosk_width_pct))
    db.set_state('kiosk_chat_height',   str(kiosk_height))
    payload = {
        'kiosk_enabled': kiosk_enabled, 'kiosk_position': kiosk_position,
        'kiosk_width_pct': kiosk_width_pct, 'kiosk_height': kiosk_height,
    }
    extensions.socketio.emit('chat_settings', payload)
    return '', 204
