import os
from flask import (
    Blueprint,
    render_template,
    redirect,
    url_for,
    flash,
    request,
    jsonify,
    send_file,
    abort,
)
from flask_login import login_required, current_user
from flask_wtf import FlaskForm
from flask_wtf.file import FileField, FileRequired
from wtforms import StringField, TextAreaField, SubmitField, HiddenField
from wtforms.validators import DataRequired, Length
from werkzeug.utils import secure_filename

from services.document_service import (
    add_document,
    add_version,
    get_document,
    get_project_documents,
    get_document_version,
    get_latest_version,
    register_download,
    delete_document,
)
from services.project_service import get_project
from services.schema_service import get_schema_document_types
from utils.security import permission_required

# Definir Blueprint
documents_bp = Blueprint("documents", __name__, url_prefix="/documents")


# Formularios
class DocumentUploadForm(FlaskForm):
    """Formulario para subir documento."""

    nombre = StringField(
        "Nombre del documento", validators=[DataRequired(), Length(1, 100)]
    )
    description = TextAreaField("Descripción", validators=[Length(0, 500)])
    file = FileField("Archivo", validators=[FileRequired()])
    submit = SubmitField("Subir documento")


class DocumentVersionForm(FlaskForm):
    """Formulario para nueva versión de documento."""

    description = TextAreaField(
        "Descripción de la versión", validators=[Length(0, 500)]
    )
    file = FileField("Archivo", validators=[FileRequired()])
    document_id = HiddenField("ID de documento", validators=[DataRequired()])
    submit = SubmitField("Subir nueva versión")


# Rutas
@documents_bp.route("/<project_id>")
@login_required
def list(project_id):
    """Listar documentos de un proyecto."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    documents = get_project_documents(project_id)

    return render_template("documents/list.html", project=project, documents=documents)


@documents_bp.route("/<project_id>/upload", methods=["GET", "POST"])
@login_required
@permission_required(1000)  # Nivel mínimo para subir documentos
def upload(project_id):
    """Subir un nuevo documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    # Verificar que el proyecto esté activo
    if project["estado"] != "activo":
        flash("No se pueden añadir documentos a un proyecto inactivo.", "warning")
        return redirect(url_for("projects.view", project_id=project_id))

    form = DocumentUploadForm()

    if form.validate_on_submit():
        # Añadir documento
        success, message, document_id = add_document(
            project_id,
            {"nombre": form.nombre.data, "description": form.description.data},
            form.file.data,
            current_user.username,
        )

        if success:
            flash(message, "success")
            return redirect(
                url_for(
                    "documents.versions", project_id=project_id, document_id=document_id
                )
            )
        else:
            flash(message, "danger")

    return render_template("documents/upload.html", form=form, project=project)


@documents_bp.route("/<project_id>/<int:document_id>")
@login_required
def versions(project_id, document_id):
    """Ver versiones de un documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    document = get_document(project_id, document_id)

    if not document:
        flash("Documento no encontrado.", "danger")
        return redirect(url_for("projects.view", project_id=project_id))

    form = DocumentVersionForm()
    form.document_id.data = document_id

    return render_template(
        "documents/versions.html", project=project, document=document, form=form
    )


@documents_bp.route("/<project_id>/<int:document_id>/upload", methods=["POST"])
@login_required
@permission_required(1000)  # Nivel mínimo para subir versiones
def upload_version(project_id, document_id):
    """Subir una nueva versión de documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    # Verificar que el proyecto esté activo
    if project["estado"] != "activo":
        flash("No se pueden añadir versiones a un proyecto inactivo.", "warning")
        return redirect(url_for("projects.view", project_id=project_id))

    document = get_document(project_id, document_id)

    if not document:
        flash("Documento no encontrado.", "danger")
        return redirect(url_for("projects.view", project_id=project_id))

    form = DocumentVersionForm()

    if form.validate_on_submit():
        # Añadir versión
        success, message, version = add_version(
            project_id,
            document_id,
            {"description": form.description.data},
            form.file.data,
            current_user.username,
        )

        if success:
            flash(message, "success")
        else:
            flash(message, "danger")
    else:
        for field, errors in form.errors.items():
            for error in errors:
                flash(f"{getattr(form, field).label.text}: {error}", "danger")

    return redirect(
        url_for("documents.versions", project_id=project_id, document_id=document_id)
    )


@documents_bp.route("/<project_id>/<int:document_id>/download/<int:version>")
@login_required
def download(project_id, document_id, version):
    """Descargar una versión específica de un documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    # Obtener versión solicitada
    version_meta, file_path = get_document_version(project_id, document_id, version)

    if not version_meta or not file_path:
        flash("Versión de documento no encontrada.", "danger")
        return redirect(url_for("projects.view", project_id=project_id))

    # Registrar descarga
    register_download(project_id, document_id, version, current_user.username)

    # Enviar archivo
    try:
        return send_file(
            file_path,
            mimetype=version_meta["mime_type"],
            as_attachment=True,
            download_name=os.path.basename(file_path),
        )
    except Exception as e:
        flash(f"Error al descargar el archivo: {str(e)}", "danger")
        return redirect(
            url_for(
                "documents.versions", project_id=project_id, document_id=document_id
            )
        )


@documents_bp.route("/<project_id>/<int:document_id>/latest")
@login_required
def download_latest(project_id, document_id):
    """Descargar la última versión de un documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    # Obtener última versión
    version_meta, file_path = get_latest_version(project_id, document_id)

    if not version_meta or not file_path:
        flash("Documento no encontrado.", "danger")
        return redirect(url_for("projects.view", project_id=project_id))

    # Registrar descarga
    register_download(
        project_id, document_id, version_meta["version"], current_user.username
    )

    # Enviar archivo
    try:
        return send_file(
            file_path,
            mimetype=version_meta["mime_type"],
            as_attachment=True,
            download_name=os.path.basename(file_path),
        )
    except Exception as e:
        flash(f"Error al descargar el archivo: {str(e)}", "danger")
        return redirect(
            url_for(
                "documents.versions", project_id=project_id, document_id=document_id
            )
        )


@documents_bp.route("/<project_id>/<int:document_id>/delete", methods=["POST"])
@login_required
@permission_required(9000)  # Nivel alto para eliminar documentos
def delete(project_id, document_id):
    """Eliminar un documento."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    success, message = delete_document(project_id, document_id)

    if success:
        flash(message, "success")
    else:
        flash(message, "danger")

    return redirect(url_for("projects.view", project_id=project_id))


@documents_bp.route("/<project_id>/export")
@login_required
def export(project_id):
    """Exportar documentos de un proyecto."""
    project = get_project(project_id)

    if not project:
        flash("Proyecto no encontrado.", "danger")
        return redirect(url_for("projects.list"))

    documents = get_project_documents(project_id)

    return render_template(
        "documents/export.html", project=project, documents=documents
    )


@documents_bp.route("/<project_id>/api/list")
@login_required
def api_list(project_id):
    """API para listar documentos de un proyecto."""
    documents = get_project_documents(project_id)

    return jsonify(documents)
