from datetime import datetime
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.transactions import LoanRequest, Loan, Document, Credit
from app.services.loan_service import check_loan_eligibility, create_loan_request, process_loan_request
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
from sqlalchemy import func


@api_bp.get("/loans/eligibility")
@jwt_required()
def loan_eligibility():
    user = User.query.get(get_jwt_identity())
    return ok(check_loan_eligibility(user))


@api_bp.post("/loan-requests")
@jwt_required()
def create_loan_request_api():
    user = User.query.get(get_jwt_identity())
    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 {})
    loan_request, error = create_loan_request(user, data, document_id=document_id)
    if error:
        return fail(error, 403)
    return ok({"request_id": loan_request.request_id}, "Loan request submitted", 201)


@api_bp.get("/loan-requests")
@role_required("administrator")
def list_loan_requests():
    requests = LoanRequest.query.order_by(LoanRequest.created_at.desc()).all()
    data = [
        {
            "id": lr.id,
            "request_id": lr.request_id,
            "member_id": lr.member_id,
            "amount": lr.amount,
            "reason": lr.reason,
            "term_months": lr.term_months,
            "status": lr.status,
            "created_at": lr.created_at.isoformat(),
        }
        for lr in requests
    ]
    return ok(data)


@api_bp.get("/loan-requests/my")
@jwt_required()
def list_my_loan_requests():
    user = User.query.get(get_jwt_identity())
    from app.models.master import SavingsPlanMember
    member_ids = [m.member_id for m in SavingsPlanMember.query.filter_by(user_id=user.id).all()]
    if not member_ids:
        return ok([])
    requests = LoanRequest.query.filter(LoanRequest.member_id.in_(member_ids)).order_by(LoanRequest.created_at.desc()).all()
    data = [
        {
            "id": lr.id,
            "request_id": lr.request_id,
            "member_id": lr.member_id,
            "amount": lr.amount,
            "reason": lr.reason,
            "term_months": lr.term_months,
            "status": lr.status,
            "created_at": lr.created_at.isoformat(),
        }
        for lr in requests
    ]
    return ok(data)


@api_bp.get("/loan-requests/view")
@jwt_required()
def list_loan_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 = LoanRequest.query.order_by(LoanRequest.created_at.desc()).all()
    data = [
        {
            "id": lr.id,
            "request_id": lr.request_id,
            "member_id": lr.member_id,
            "member_short_name": lr.member.member_short_name if lr.member else None,
            "user_full_name": lr.member.user.full_name if lr.member and lr.member.user else None,
            "amount": lr.amount,
            "term_months": lr.term_months,
            "status": lr.status,
            "created_at": lr.created_at.isoformat(),
        }
        for lr in requests
    ]
    return ok(data)


@api_bp.put("/loan-requests/<string:request_id>")
@role_required("administrator")
def update_loan_request(request_id):
    request_obj = LoanRequest.query.filter_by(request_id=request_id).first_or_404()
    data = request.json or {}
    status = data.get("status")
    cashier_id = data.get("cashier_id")
    allocations = data.get("allocations")
    force = bool(data.get("force", False))
    if status not in ["approved", "rejected", "pending", "released"]:
        return fail("Invalid status", 400)

    try:
        process_loan_request(request_obj, status=status, cashier_id=cashier_id, allocations=allocations, force=force)
    except ValueError as e:
        return fail(str(e), 400)
    return ok({"request_id": request_obj.request_id}, "Loan request updated")


@api_bp.get("/loans")
@jwt_required()
def list_loans():
    user = User.query.get(get_jwt_identity())
    query = Loan.query
    if user.access_level == "member":
        from app.models.master import SavingsPlanMember
        member = SavingsPlanMember.query.filter_by(user_id=user.id, status="active").first()
        if member:
            query = query.filter_by(member_id=member.member_id)
        else:
            query = query.filter_by(member_id="")

    loans = query.order_by(Loan.created_at.desc()).all()
    data = [
        {
            "id": loan.id,
            "loan_id": loan.loan_id,
            "member_id": loan.member_id,
            "request_id": loan.request_id,
            "amount": loan.amount,
            "term_months": loan.term_months,
            "status": loan.status,
            "created_at": loan.created_at.isoformat(),
            "disbursement_date": loan.disbursement_date.isoformat() if loan.disbursement_date else None,
        }
        for loan in loans
    ]
    return ok(data)


@api_bp.get("/loans/member/<string:member_id>/active")
@jwt_required()
def member_active_loans(member_id):
    active_loans = Loan.query.filter_by(member_id=member_id, status="active").all()
    loans_data = []
    for loan in active_loans:
        paid_amount = db.session.query(func.sum(Credit.total_amount)).filter(
            Credit.loan_id == loan.loan_id,
            Credit.transaction_type == "emi",
        ).scalar() or 0
        if paid_amount < loan.amount:
            loans_data.append({
                "loan_id": loan.loan_id,
                "amount": loan.amount,
                "paid_amount": paid_amount,
                "outstanding": loan.amount - paid_amount,
            })
    return ok({"loans": loans_data})


@api_bp.put("/loans/<string:loan_id>")
@role_required("administrator")
def update_loan(loan_id):
    loan = Loan.query.filter_by(loan_id=loan_id).first_or_404()
    data = request.json or {}
    if "status" in data:
        loan.status = data["status"]
    if "disbursement_date" in data:
        loan.disbursement_date = datetime.strptime(data["disbursement_date"], "%Y-%m-%d").date()

    db.session.commit()

    create_notification(
        user_id=loan.member.user_id if loan.member else None,
        title="Loan updated",
        message=f"Loan {loan.loan_id} status updated to {loan.status}.",
        notif_type="info",
        link="/app/requests",
    )

    return ok({"loan_id": loan.loan_id}, "Loan updated")
