from datetime import datetime
import os
from werkzeug.utils import secure_filename
from flask import Blueprint, render_template, request, redirect, url_for, flash, current_app
from flask_login import login_required

from models import (
    db,
    SalarySlipTemplate,
    SalarySlipFieldConfig,
    SalarySlipComponentConfig,
    EarningHead,
    DeductionHead,
    CTCHead,
    Employee
)

salary_slip_template_bp = Blueprint("salary_slip_template", __name__, url_prefix="/salary-slip-template")


EMPLOYEE_FIELDS = [
    ("employee_name", "Employee Name"),
    ("employee_code", "Employee Code"),
    ("department", "Department"),
    ("designation", "Designation"),
    ("date_of_joining", "Date of Joining"),
    ("uan", "UAN"),
    ("pan_number", "PAN"),
    ("bank_name", "Bank Name"),
    ("bank_account_number", "Bank Account Number"),
    ("ifsc_code", "IFSC Code"),
    ("location", "Location"),
]

COMPANY_FIELDS = [
    ("company_name", "Company Name"),
    ("company_address", "Company Address"),
    ("company_contact", "Company Contact"),
    ("footer_text", "Footer Text"),
]

ATTENDANCE_FIELDS = [
    ("total_days", "Paid Days"),
    ("present", "Present"),
    ("leave", "Leave"),
    ("lwp", "LWP"),
    ("holidays", "Holidays"),
    ("weekends", "Weekends"),
]


def _save_template_logo(file_storage):
    if not file_storage or not file_storage.filename:
        return None

    filename = secure_filename(file_storage.filename)
    ext = filename.rsplit(".", 1)[-1].lower() if "." in filename else ""
    if ext not in {"png", "jpg", "jpeg", "webp", "svg"}:
        return None

    upload_dir = os.path.join(current_app.root_path, "static", "uploads", "salary_slip_logos")
    os.makedirs(upload_dir, exist_ok=True)

    stamped_name = f"{datetime.utcnow().strftime('%Y%m%d%H%M%S%f')}_{filename}"
    full_path = os.path.join(upload_dir, stamped_name)
    file_storage.save(full_path)

    return f"/static/uploads/salary_slip_logos/{stamped_name}"


@salary_slip_template_bp.route("/", methods=["GET", "POST"])
@login_required
def manage_templates():
    if request.method == "POST":
        template_id = request.form.get("template_id")
        template_name = (request.form.get("template_name") or "").strip()

        if not template_name:
            flash("Template Name is required.", "danger")
            return redirect(url_for("salary_slip_template.manage_templates"))

        if template_id:
            template = SalarySlipTemplate.query.get_or_404(template_id)
        else:
            template = SalarySlipTemplate()
            db.session.add(template)

        template.template_name = template_name
        template.scope_type = request.form.get("scope_type") or "global"
        template.location = request.form.get("location") or None
        template.institute = request.form.get("institute") or None
        template.is_active = True if request.form.get("is_active") == "on" else False

        template.show_company_section = True if request.form.get("show_company_section") == "on" else False
        template.show_employee_section = True if request.form.get("show_employee_section") == "on" else False
        template.show_attendance_section = True if request.form.get("show_attendance_section") == "on" else False
        template.show_ctc_section = True if request.form.get("show_ctc_section") == "on" else False
        template.show_footer = True if request.form.get("show_footer") == "on" else False
        template.show_amount_in_words = True if request.form.get("show_amount_in_words") == "on" else False

        template.company_name = request.form.get("company_name") or None
        template.company_address = request.form.get("company_address") or None
        template.company_contact = request.form.get("company_contact") or None
        template.footer_text = request.form.get("footer_text") or None
        template.updated_on = datetime.utcnow()

        # logo upload / clear
        if request.form.get("remove_logo") == "on":
            template.logo_path = None

        logo_file = request.files.get("logo_file")
        saved_logo = _save_template_logo(logo_file)
        if logo_file and logo_file.filename and not saved_logo:
            flash("Invalid logo file. Allowed: png, jpg, jpeg, webp, svg", "danger")
            return redirect(url_for("salary_slip_template.manage_templates", template_id=template.id))

        if saved_logo:
            template.logo_path = saved_logo

        db.session.flush()

        SalarySlipFieldConfig.query.filter_by(template_id=template.id).delete()
        SalarySlipComponentConfig.query.filter_by(template_id=template.id).delete()

        all_fields = [
            ("employee", EMPLOYEE_FIELDS),
            ("company", COMPANY_FIELDS),
            ("attendance", ATTENDANCE_FIELDS),
        ]

        for section_name, fields in all_fields:
            for idx, (key, label) in enumerate(fields, start=1):
                is_visible = request.form.get(f"field_visible__{section_name}__{key}") == "on"
                display_label = request.form.get(f"field_label__{section_name}__{key}") or label

                db.session.add(SalarySlipFieldConfig(
                    template_id=template.id,
                    section_name=section_name,
                    field_key=key,
                    display_label=display_label,
                    is_visible=is_visible,
                    display_order=idx
                ))

        earning_heads = EarningHead.query.all()
        deduction_heads = DeductionHead.query.all()
        ctc_heads = CTCHead.query.all()

        for idx, head in enumerate(earning_heads, start=1):
            db.session.add(SalarySlipComponentConfig(
                template_id=template.id,
                component_type="earning",
                head_name=head.name,
                display_label=request.form.get(f"earning_label__{head.name}") or head.name,
                is_visible=request.form.get(f"earning_visible__{head.name}") == "on",
                display_order=idx
            ))

        for idx, head in enumerate(deduction_heads, start=1):
            db.session.add(SalarySlipComponentConfig(
                template_id=template.id,
                component_type="deduction",
                head_name=head.name,
                display_label=request.form.get(f"deduction_label__{head.name}") or head.name,
                is_visible=request.form.get(f"deduction_visible__{head.name}") == "on",
                display_order=idx
            ))

        for idx, head in enumerate(ctc_heads, start=1):
            db.session.add(SalarySlipComponentConfig(
                template_id=template.id,
                component_type="ctc",
                head_name=head.name,
                display_label=request.form.get(f"ctc_label__{head.name}") or head.name,
                is_visible=request.form.get(f"ctc_visible__{head.name}") == "on",
                display_order=idx
            ))

        db.session.commit()
        flash("Salary slip template saved successfully.", "success")
        return redirect(url_for("salary_slip_template.manage_templates", template_id=template.id))

    templates = SalarySlipTemplate.query.order_by(SalarySlipTemplate.id.desc()).all()
    selected_template_id = request.args.get("template_id", type=int)
    selected_template = SalarySlipTemplate.query.get(selected_template_id) if selected_template_id else None

    locations = [x[0] for x in db.session.query(Employee.location).filter(Employee.location.isnot(None)).distinct().all()]
    institutes = [x[0] for x in db.session.query(Employee.institute).filter(Employee.institute.isnot(None)).distinct().all()]

    earning_heads = EarningHead.query.order_by(EarningHead.name.asc()).all()
    deduction_heads = DeductionHead.query.order_by(DeductionHead.name.asc()).all()
    ctc_heads = CTCHead.query.order_by(CTCHead.name.asc()).all()

    field_map = {}
    component_map = {}

    if selected_template:
        for f in selected_template.field_configs:
            field_map[(f.section_name, f.field_key)] = f

        for c in selected_template.component_configs:
            component_map[(c.component_type, c.head_name)] = c

    return render_template(
        "salary_slip_template/manage.html",
        templates=templates,
        selected_template=selected_template,
        locations=locations,
        institutes=institutes,
        employee_fields=EMPLOYEE_FIELDS,
        company_fields=COMPANY_FIELDS,
        attendance_fields=ATTENDANCE_FIELDS,
        earning_heads=earning_heads,
        deduction_heads=deduction_heads,
        ctc_heads=ctc_heads,
        field_map=field_map,
        component_map=component_map
    )