import random
import string
from datetime import datetime
from sqlalchemy import func
from app.extensions import db
from app.models.transactions import Credit, Loan
from app.services.notification_service import create_notification
from app.services.email_service import send_templated_email


def generate_transaction_id():
    prefix = "TR"
    date_part = datetime.now().strftime("%y%m%d")
    while True:
        random_part = "".join(random.choices(string.digits, k=4))
        transaction_id = f"{prefix}{date_part}{random_part}"
        if not Credit.query.filter_by(transaction_id=transaction_id).first():
            return transaction_id


def add_credit(data, cashier_id=None, actor_user_id=None):
    member_id = data["member_id"]
    transaction_type = data["transaction_type"]
    total_amount = float(data["total_amount"])
    transaction_date = datetime.strptime(data["transaction_date"], "%Y-%m-%d").date()
    savings_amount = float(data.get("savings_amount") or 0)
    charity_amount = float(data.get("charity_amount") or 0)

    if transaction_type == "savings":
        year = transaction_date.year
        month = transaction_date.month
        existing_savings = Credit.query.filter(
            Credit.member_id == member_id,
            Credit.transaction_type == "savings",
            func.extract("year", Credit.transaction_date) == year,
            func.extract("month", Credit.transaction_date) == month,
        ).first()
        if existing_savings:
            return None, "A savings transaction already exists for this member in the selected month. Use flexi savings for additional entries.", False

    db_transaction_type = "savings" if transaction_type == "flexi" else transaction_type

    loan_id = data.get("loan_id") if transaction_type == "emi" else None
    loan_closed = False

    transaction_id = generate_transaction_id()

    new_credit = Credit(
        transaction_id=transaction_id,
        member_id=member_id,
        transaction_type=db_transaction_type,
        total_amount=total_amount,
        savings_amount=savings_amount,
        charity_amount=charity_amount,
        loan_id=loan_id,
        cashier_id=cashier_id,
        transaction_date=transaction_date,
    )

    db.session.add(new_credit)

    if transaction_type == "emi" and loan_id:
        loan = Loan.query.filter_by(loan_id=loan_id).first()
        if loan:
            total_paid = db.session.query(func.sum(Credit.total_amount)).filter(
                Credit.loan_id == loan_id,
                Credit.transaction_type == "emi",
            ).scalar() or 0
            total_paid += total_amount
            if total_paid >= loan.amount:
                loan.status = "closed"
                db.session.add(loan)
                loan_closed = True

    db.session.commit()

    if actor_user_id:
        create_notification(
            user_id=actor_user_id,
            title="Credit posted",
            message=f"Credit {transaction_id} posted for member {member_id}.",
            notif_type="success",
            link=f"/app/credits/{new_credit.id}",
        )

    return new_credit, None, loan_closed


def notify_credit_member(user, credit, display_type):
    if not user or not user.email:
        return
    send_templated_email(
        to=user.email,
        subject="Credit Transaction Successful",
        template="emails/credit_posted.html",
        cc_admin=False,
        member_name=user.full_name,
        transaction_id=credit.transaction_id,
        amount=credit.total_amount,
        date=credit.transaction_date.strftime("%Y-%m-%d"),
        transaction_type=display_type,
    )
