# ============================================================
# routes_strategy.py
# ============================================================

import os
import uuid
from datetime import datetime, timezone
from flask import (Blueprint, render_template, request, redirect,
                   url_for, flash, jsonify, send_from_directory,
                   current_app)
from flask_login import login_required, current_user
from werkzeug.utils import secure_filename

from models import StrategyPost, StrategyFile, StrategyLastSeen
from models import db

strategy_bp = Blueprint('strategy', __name__, url_prefix='/strategy')

# ── Extensiones permitidas ─────────────────────────────────────────
ALLOWED_EXTENSIONS = {'csv', 'xlsx', 'xls', 'pdf', 'png', 'jpg', 'jpeg',
                      'gif', 'webp', 'txt', 'zip', 'py', 'json',
                      'mp4', 'webm', 'mov', 'html'}

VIDEO_EXTENSIONS  = {'mp4', 'webm', 'mov'}
MAX_SIZE_VIDEO    = 20  * 1024 * 1024   # 20 MB
MAX_SIZE_DEFAULT  = 10  * 1024 * 1024   # 10 MB

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

def allowed_size(filename, file_obj):
    """Devuelve True si el archivo está dentro del límite de tamaño."""
    ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else ''
    limit = MAX_SIZE_VIDEO if ext in VIDEO_EXTENSIONS else MAX_SIZE_DEFAULT
    file_obj.seek(0, 2)          # ir al final
    size = file_obj.tell()
    file_obj.seek(0)             # rebobinar
    return size <= limit, size, limit

def get_file_type(filename):
    ext = filename.rsplit('.', 1)[1].lower() if '.' in filename else 'other'
    if ext in {'csv', 'xlsx', 'xls'}:
        return 'csv'
    if ext in {'png', 'jpg', 'jpeg', 'gif', 'webp'}:
        return 'image'
    if ext in VIDEO_EXTENSIONS:
        return 'video'
    if ext == 'pdf':
        return 'pdf'
    if ext == 'html':
        return 'html'
    return 'other'

def upload_dir():
    path = os.path.join(current_app.root_path, 'uploads', 'strategies')
    os.makedirs(path, exist_ok=True)
    return path

def _is_admin():
    allowed = set(
        e.strip().lower()
        for e in os.getenv("ADMIN_ALLOWED_EMAILS", "").split(",")
        if e.strip()
    )
    return current_user.email.lower() in allowed


# ── GET /strategy/<code>  — workspace ─────────────────────────────
@strategy_bp.route('/<code>')
@login_required
def workspace(code):
    code = code.upper()

    posts = StrategyPost.query\
            .filter_by(strategy_code=code, parent_id=None)\
            .order_by(StrategyPost.created_at.desc())\
            .all()

    # ── Actualizar last_seen del usuario ───────────────────────
    seen = StrategyLastSeen.query.filter_by(
        user_id=current_user.id, strategy_code=code
    ).first()
    if seen:
        seen.last_seen_at = datetime.now(timezone.utc)
    else:
        db.session.add(StrategyLastSeen(
            user_id=current_user.id,
            strategy_code=code
        ))
    db.session.commit()
    # ──────────────────────────────────────────────────────────

    return render_template('strategy_workspace.html',
                           code=code,
                           posts=posts,
                           is_admin=_is_admin())


# ── POST /strategy/<code>/post  — enviar mensaje ───────────────────
@strategy_bp.route('/<code>/post', methods=['POST'])
@login_required
def add_post(code):
    code    = code.upper()
    content = request.form.get('content', '').strip()

    if not content:
        flash('El mensaje no puede estar vacío.', 'warning')
        return redirect(url_for('strategy.workspace', code=code))

    post = StrategyPost(
        strategy_code=code,
        user_id=current_user.id,
        content=content,
        post_type='message'
    )
    db.session.add(post)
    db.session.flush()

    # Soporta múltiples archivos con el campo 'attachments'
    files = request.files.getlist('attachments')
    for file in files:
        if file and file.filename and allowed_file(file.filename):
            ok, size, limit = allowed_size(file.filename, file)
            if not ok:
                mb = limit // (1024 * 1024)
                flash(f'"{file.filename}" supera el límite de {mb} MB.', 'warning')
                continue
            _save_file(file, code, post.id)

    db.session.commit()
    return redirect(url_for('strategy.workspace', code=code))


# ── POST /strategy/<code>/post/<id>/reply  — responder mensaje ────
@strategy_bp.route('/<code>/post/<int:post_id>/reply', methods=['POST'])
@login_required
def add_reply(code, post_id):
    code = code.upper()

    parent = StrategyPost.query.filter_by(
        id=post_id, strategy_code=code
    ).first_or_404()

    if parent.parent_id is not None:
        return jsonify({'error': 'No se puede responder a una respuesta'}), 400

    content = request.form.get('content', '').strip()
    if not content:
        return jsonify({'error': 'El mensaje no puede estar vacío'}), 400

    reply = StrategyPost(
        strategy_code=code,
        user_id=current_user.id,
        content=content,
        post_type='reply',
        parent_id=post_id
    )
    db.session.add(reply)
    db.session.flush()

    files = request.files.getlist('attachments')
    for file in files:
        if file and file.filename and allowed_file(file.filename):
            ok, size, limit = allowed_size(file.filename, file)
            if not ok:
                continue
            _save_file(file, code, reply.id)

    db.session.commit()
    return jsonify({
        'ok': True,
        'reply': {
            'id':        reply.id,
            'author':    current_user.username,
            'content':   reply.content,
            'time':      reply.created_at.strftime('%H:%M'),
            'parent_id': post_id,
        }
    }), 200


# ── POST /strategy/<code>/post/<id>/edit  — editar mensaje ────────
@strategy_bp.route('/<code>/post/<int:post_id>/edit', methods=['POST'])
@login_required
def edit_post(code, post_id):
    post = StrategyPost.query.filter_by(
        id=post_id, strategy_code=code.upper()
    ).first_or_404()

    if post.user_id != current_user.id:
        return jsonify({'error': 'Sin permiso'}), 403

    if request.is_json:
        content = request.json.get('content', '').strip()
    else:
        content = request.form.get('content', '').strip()

    if not content:
        return jsonify({'error': 'Contenido vacío'}), 400

    post.content = content

    files_data = []
    new_files = request.files.getlist('attachments')
    for file in new_files:
        if file and file.filename and allowed_file(file.filename):
            ok, size, limit = allowed_size(file.filename, file)
            if not ok:
                mb = limit // (1024 * 1024)
                return jsonify({'error': f'"{file.filename}" supera el límite de {mb} MB.'}), 413
            try:
                sf = _save_file(file, code.upper(), post.id)
                db.session.flush()
                files_data.append({
                    'id': sf.id,
                    'original_name': sf.original_name,
                    'filename': sf.filename,
                })
            except (OSError, PermissionError) as e:
                db.session.rollback()
                return jsonify({'error': f'Error al guardar archivo: {e}'}), 500

    db.session.commit()
    return jsonify({'ok': True, 'content': post.content, 'files': files_data}), 200


# ── DELETE /strategy/<code>/post/<id>  — borrar mensaje ───────────
@strategy_bp.route('/<code>/post/<int:post_id>', methods=['DELETE'])
@login_required
def delete_post(code, post_id):
    post = StrategyPost.query.filter_by(
        id=post_id, strategy_code=code.upper()
    ).first_or_404()

    if post.user_id != current_user.id and not _is_admin():
        return jsonify({'error': 'Sin permiso'}), 403

    # ── Borrar archivos físicos antes de eliminar el post ──
    for sf in post.files:
        try:
            os.remove(os.path.join(upload_dir(), sf.filename))
        except FileNotFoundError:
            pass
        db.session.delete(sf)

    db.session.delete(post)
    db.session.commit()
    return jsonify({'deleted': post_id}), 200


# ── GET /strategy/<code>/files/<filename>  — descargar archivo ────
@strategy_bp.route('/<code>/files/<filename>')
@login_required
def download_file(code, filename):
    sf = StrategyFile.query.filter_by(
        filename=filename, strategy_code=code.upper()
    ).first_or_404()
    return send_from_directory(upload_dir(),
                               sf.filename,
                               as_attachment=True,
                               download_name=sf.original_name)


# ── GET /strategy/<code>/preview/<filename>  — preview inline ─────
@strategy_bp.route('/<code>/preview/<filename>')
@login_required
def preview_file(code, filename):
    sf = StrategyFile.query.filter_by(
        filename=filename, strategy_code=code.upper()
    ).first_or_404()
    return send_from_directory(upload_dir(),
                               sf.filename,
                               as_attachment=False)


# ── DELETE /strategy/<code>/file/<id>  — borrar archivo ───────────
@strategy_bp.route('/<code>/file/<int:file_id>', methods=['DELETE'])
@login_required
def delete_file(code, file_id):
    sf = StrategyFile.query.filter_by(
        id=file_id, strategy_code=code.upper()
    ).first_or_404()

    if sf.user_id != current_user.id and not _is_admin():
        return jsonify({'error': 'Sin permiso'}), 403

    try:
        os.remove(os.path.join(upload_dir(), sf.filename))
    except FileNotFoundError:
        pass

    db.session.delete(sf)
    db.session.commit()
    return jsonify({'deleted': file_id}), 200


# ── Helper interno ─────────────────────────────────────────────────
def _save_file(file_obj, strategy_code, post_id):
    ext    = secure_filename(file_obj.filename).rsplit('.', 1)[-1].lower()
    unique = f"{uuid.uuid4().hex}.{ext}"
    file_obj.save(os.path.join(upload_dir(), unique))

    sf = StrategyFile(
        strategy_code=strategy_code,
        user_id=current_user.id,
        post_id=post_id,
        filename=unique,
        original_name=secure_filename(file_obj.filename),
        file_type=get_file_type(file_obj.filename),
        file_size=os.path.getsize(os.path.join(upload_dir(), unique))
    )
    db.session.add(sf)
    return sf