from flask import request, current_app
from flask_jwt_extended import get_jwt_identity, jwt_required
from app.api import api_bp
from app.extensions import db
from app.models.user import User
from app.models.master import SavingsPlanMember
from app.models.transactions import CharityRequest, Document
from app.services.charity_service import generate_charity_id, update_charity_request
from app.services.email_service import send_templated_email
from app.services.notification_service import create_notification
from app.utils.auth import role_required
from app.utils.files import allowed_file, save_upload
from app.utils.response import ok, fail


@api_bp.post("/charity-requests")
@jwt_required()
def create_charity_request():
    user = User.query.get(get_jwt_identity())
    member = SavingsPlanMember.query.filter_by(user_id=user.id, status="active").first()
    if not member:
        return fail("Must be enrolled in savings plan to request Charity", 403)

    document_id = None
    if "document" in request.files:
        file = request.files["document"]
        if file and allowed_file(file.filename):
            filename, file_path, file_type, file_size = save_upload(file, current_app.config["UPLOAD_FOLDER"])
            document = Document(
                file_name=filename,
                file_path=file_path,
                file_type=file_type,
                file_size=file_size,
            )
            db.session.add(document)
            db.session.commit()
            document_id = document.id
        else:
            return fail("Invalid file type", 400)

    data = request.form.to_dict() if request.form else (request.json or {})

    charity_request = CharityRequest(
        charity_id=generate_charity_id(),
        member_id=member.member_id,
        charity_type_id=data["charity_type_id"],
        beneficiary_name=data["beneficiary_name"],
        reason=data["reason"],
        amount=float(data["amount"]),
        document_id=document_id,
        status="pending",
    )
    db.session.add(charity_request)
    db.session.commit()

    send_templated_email(
        to=user.email,
        subject="Charity Request Submitted",
        template="emails/charity_submitted.html",
        cc_admin=True,
        charity_id=charity_request.charity_id,
        beneficiary=charity_request.beneficiary_name,
        amount=charity_request.amount,
        member_name=user.full_name,
    )

    create_notification(
        user_id=user.id,
        title="Charity request submitted",
        message=f"Charity request {charity_request.charity_id} submitted.",
        notif_type="info",
        link="/app/requests",
    )

    return ok({"charity_id": charity_request.charity_id}, "Charity request submitted", 201)


@api_bp.get("/charity-requests")
@jwt_required()
def list_charity_requests():
    user = User.query.get(get_jwt_identity())
    query = CharityRequest.query
    if user.access_level == "member":
        member_ids = [m.member_id for m in SavingsPlanMember.query.filter_by(user_id=user.id).all()]
        if member_ids:
            query = query.filter(CharityRequest.member_id.in_(member_ids))
        else:
            query = query.filter_by(member_id="")
    requests = query.order_by(CharityRequest.created_at.desc()).all()
    data = [
        {
            "id": cr.id,
            "charity_id": cr.charity_id,
            "member_id": cr.member_id,
            "charity_type_id": cr.charity_type_id,
            "beneficiary_name": cr.beneficiary_name,
            "reason": cr.reason,
            "amount": cr.amount,
            "allotted_amount": cr.allotted_amount,
            "cashier_id": cr.cashier_id,
            "status": cr.status,
            "created_at": cr.created_at.isoformat(),
        }
        for cr in requests
    ]
    return ok(data)


@api_bp.get("/charity-requests/view")
@jwt_required()
def list_charity_requests_view():
    from app.services.settings_service import is_allowed

    user = User.query.get(get_jwt_identity())
    if not user:
        return fail("Unauthorized", 401)
    if user.access_level != "administrator" and not is_allowed(user.access_level, "requests.view_all"):
        return fail("Forbidden", 403)

    requests = CharityRequest.query.order_by(CharityRequest.created_at.desc()).all()
    data = [
        {
            "id": cr.id,
            "charity_id": cr.charity_id,
            "member_id": cr.member_id,
            "member_short_name": cr.member.member_short_name if cr.member else None,
            "user_full_name": cr.member.user.full_name if cr.member and cr.member.user else None,
            "charity_type_id": cr.charity_type_id,
            "charity_type": cr.charity_type.charity_type if cr.charity_type else None,
            "beneficiary_name": cr.beneficiary_name,
            "amount": cr.amount,
            "status": cr.status,
            "created_at": cr.created_at.isoformat(),
        }
        for cr in requests
    ]
    return ok(data)


@api_bp.put("/charity-requests/<int:request_id>")
@role_required("administrator")
def update_charity_request_api(request_id):
    charity_request = CharityRequest.query.get_or_404(request_id)
    data = request.json or {}
    status = data.get("status", charity_request.status)
    allotted_amount = data.get("allotted_amount")
    cashier_id = data.get("cashier_id")
    allocations = data.get("allocations")
    force = bool(data.get("force", False))

    try:
        updated = update_charity_request(charity_request, status, allotted_amount, cashier_id, allocations=allocations, force=force)
    except ValueError as e:
        return fail(str(e), 400)
    return ok({"id": updated.id}, "Charity request updated")
