# /opt/trueconf_bot/lk/payslip_service.py
import calendar
import tempfile
from itertools import zip_longest
from weasyprint import HTML
import config.config as config

# Перевод английских системных месяцев в русские наименования для бланка PDF
ENG_TO_RU_MONTHS = {
    "January": "Январь", "February": "Февраль", "March": "Март",
    "April": "Апрель", "May": "Май", "June": "Июнь",
    "July": "Июль", "August": "Август", "September": "Сентябрь",
    "October": "Октябрь", "November": "Ноябрь", "December": "Декабрь"
}

def format_currency(summa):
    try:
        if summa is None:
            return "0,00"
        f_summa = float(summa)
        return f"{f_summa:,.2f}".replace(",", " ").replace(".", ",")
    except:
        return str(summa)

def translate_period(period_str):
    if not period_str:
        return ""
    for eng, ru in ENG_TO_RU_MONTHS.items():
        if eng in period_str:
            return period_str.replace(eng, ru)
    return period_str

def get_latest_payslip_months(cursor, card_id: str) -> list:
    query = """
        SELECT DISTINCT TOP 6 (t.TYEAR * 12 + t.TMONTH) as CMONTH
        FROM UOV_SELFSERVICE_PR_EMP e
        JOIN UOV_SELFSERVICE_PR_CARD c on c.ID = e.CARD_ID
        JOIN UOV_SELFSERVICE_SL_YTAX t on t.CARD_ID = e.CARD_ID
        JOIN UOV_SELFSERVICE_PR_TRANS tr on tr.EMP_ID = e.ID
        JOIN UOV_SELFSERVICE_ST_APPOINT a on a.ID = tr.APPOINT_ID
        JOIN UOV_SELFSERVICE_HR_FIRM f on f.ID = e.FIRM_ID
        WHERE c.ID = %s
        ORDER BY CMONTH DESC
    """
    cursor.execute(query, (card_id,))
    months = cursor.fetchall()
    if not months:
        raise Exception("Отсутствуют расчетные периоды.")
    return [m[0] for m in months]

def create_payslip_pdf(month_name, target_tyear, 
                       header_sys, header_wage, header_deduct, header_base,
                       earnings_rows, deductions_rows, noncash_rows, payout_rows,
                       total_earned, total_withheld, total_noncash, total_payouts,
                       debt_comp_start, debt_emp_start, debt_comp_end, debt_emp_end, net_pay):
    tbody_html = ""
    tbody_html += f"""
        <tr>
            <td colspan="6" class="section-title">1. Начислено</td>
            <td colspan="4" class="section-title">2. Удержано</td>
        </tr>
    """
    
    for earn, ded in zip_longest(earnings_rows, deductions_rows):
        if earn:
            earn_name = str(earn[0]).strip()
            earn_days = f"{earn[1]:g}".replace('.', ',') if earn[1] else ""
            earn_hours = f"{earn[2]:g}".replace('.', ',') if earn[2] else ""
            earn_prc = f"{earn[3]:g}" if earn[3] else ""
            earn_period = translate_period(earn[4] or "")
            earn_summa = format_currency(earn[5])
            earn_html = f'<td class="left-align">{earn_name}</td><td class="center-align">{earn_days}</td><td class="center-align">{earn_hours}</td><td class="center-align">{earn_prc}</td><td class="center-align">{earn_period}</td><td>{earn_summa}</td>'
        else:
            earn_html = '<td style="border-bottom: none; border-left: none;"></td><td style="border-bottom: none;"></td><td style="border-bottom: none;"></td><td style="border-bottom: none;"></td><td style="border-bottom: none;"></td><td style="border-bottom: none; border-right: none;"></td>'
            
        if ded:
            ded_name = str(ded[0]).strip()
            ded_prc = f"{ded[1]:.0f}" if ded[1] else ""
            ded_period = translate_period(ded[2] or "")
            ded_summa = format_currency(ded[3])
            ded_html = f'<td class="left-align">{ded_name}</td><td class="center-align">{ded_prc}</td><td class="center-align">{ded_period}</td><td>{ded_summa}</td>'
        else:
            ded_html = '<td style="border-bottom: none; border-left: none; border-right: none;" colspan="4"></td>'
            
        tbody_html += f"<tr>{earn_html}{ded_html}</tr>"

    tbody_html += f"""
        <tr class="totals">
            <td class="left-align" colspan="5">Всего начислено</td><td>{format_currency(total_earned)}</td>
            <td class="left-align" colspan="3">Всего удержано</td><td>{format_currency(total_withheld)}</td>
        </tr>
        <tr>
            <td colspan="6" class="section-title">3. Доходы в неденежной форме</td>
            <td colspan="4" class="section-title">4. Выплачено</td>
        </tr>
    """
    
    for nc, pay in zip_longest(noncash_rows, payout_rows):
        if nc:
            nc_name = str(nc[0]).strip()
            nc_period = translate_period(nc[1] or "")
            nc_summa = format_currency(nc[2])
            nc_html = f'<td class="left-align" colspan="4">{nc_name}</td><td class="center-align">{nc_period}</td><td>{nc_summa}</td>'
        else:
            nc_html = '<td style="border-top: none; border-bottom: none; border-left: none;"></td><td style="border-top: none; border-bottom: none;"></td><td style="border-top: none; border-bottom: none;"></td><td style="border-top: none; border-bottom: none;"></td><td style="border-top: none; border-bottom: none;"></td><td style="border-top: none; border-bottom: none; border-right: none;"></td>'
            
        if pay:
            pay_name = str(pay[0]).strip()
            pay_period = translate_period(pay[1] or "")
            pay_summa = format_currency(pay[2])
            pay_html = f'<td class="left-align" colspan="2">{pay_name}</td><td class="center-align">{pay_period}</td><td>{pay_summa}</td>'
        else:
            pay_html = '<td style="border-top: none; border-bottom: none; border-left: none; border-right: none;" colspan="4"></td>'
            
        tbody_html += f"<tr>{nc_html}{pay_html}</tr>"

    tbody_html += f"""
        <tr class="totals">
            <td class="left-align" colspan="5">Всего доходов в неденежной форме</td><td>{format_currency(total_noncash)}</td>
            <td class="left-align" colspan="3">Всего выплачено</td><td>{format_currency(total_payouts)}</td>
        </tr>
        <tr>
            <td class="left-align" colspan="5">Долг за предприятием на начало месяца</td><td>{format_currency(debt_comp_start)}</td>
            <td class="left-align" colspan="3">Долг за предприятием на конец месяца</td><td>{format_currency(debt_comp_end)}</td>
        </tr>
        <tr>
            <td class="left-align" colspan="5">Долг за работником на начало месяца</td><td>{format_currency(debt_emp_start)}</td>
            <td class="left-align" colspan="3">Долг за работником на конец месяца</td><td>{format_currency(debt_emp_end)}</td>
        </tr>
        <tr class="totals">
            <td colspan="6" class="empty-cell"></td>
            <td class="left-align section-title" colspan="3"><b>5. Выплачено денежными средствами</b></td><td class="section-title"><b>{format_currency(net_pay)}</b></td>
        </tr>
    """

    html_template = f"""
    <!DOCTYPE html>
    <html lang="ru">
    <head>
        <meta charset="UTF-8">
        <style>
            @page {{ size: A4 landscape; margin: 15mm; background-color: #ffffff; }}
            body {{ font-family: Arial, sans-serif; font-size: 11px; color: #333; margin: 0; padding: 0; }}
            h2 {{ text-align: center; margin-bottom: 15px; font-size: 16px; font-weight: normal; }}
            table {{ width: 100%; border-collapse: collapse; margin-bottom: 10px; }}
            th, td {{ border: 1px solid #a0a0a0; padding: 5px 8px; text-align: right; vertical-align: middle; }}
            th {{ background-color: #f2f2f2; text-align: center; font-weight: normal; color: #555; }}
            .header-table td {{ border: 1px solid #a0a0a0; text-align: left; background-color: #fcfcfc; }}
            .left-align {{ text-align: left; }}
            .center-align {{ text-align: center; }}
            .section-title {{ background-color: #fcfcfc; font-weight: bold; text-align: left; padding-top: 10px; padding-bottom: 10px; }}
            .totals {{ background-color: #fcfcfc; font-weight: bold; }}
            .empty-cell {{ border: none; }}
        </style>
    </head>
    <body>
        <h2><b>Расчетный лист за {month_name} {target_tyear} г.</b></h2>
        <table class="header-table" style="margin-bottom: 15px;">
            <tr><td style="width: 60%;">Система оплаты: {header_sys}</td><td style="width: 40%;">Оклад: {format_currency(header_wage)}</td></tr>
            <tr><td colspan="2">Стандартные вычеты за месяц: {format_currency(header_deduct)}</td></tr>
            <tr><td colspan="2">Облагаемая база по ставке 13%: {format_currency(header_base)}</td></tr>
        </table>
        <table>
            <thead>
                <tr>
                    <th style="width: 20%;">Вид</th><th>Дни</th><th>Часы</th><th>%</th><th>Период</th><th>Сумма</th>
                    <th style="width: 20%;">Вид</th><th>%</th><th>Период</th><th>Сумма</th>
                </tr>
            </thead>
            <tbody>
                {tbody_html}
            </tbody>
        </table>
    </body>
    </html>
    """
    temp_pdf = tempfile.NamedTemporaryFile(delete=False, suffix='.pdf')
    HTML(string=html_template).write_pdf(temp_pdf.name)
    return temp_pdf.name

def build_payslip_data(cursor, card_id: str, target_cmonth: int) -> tuple:
    tyear = (target_cmonth - 1) // 12
    tmonth = (target_cmonth - 1) % 12 + 1
    _, last_day = calendar.monthrange(tyear, tmonth)
    
    date_start = f"{tyear}-{tmonth:02d}-01"
    date_end = f"{tyear}-{tmonth:02d}-{last_day:02d}"
    date_params = (date_start, date_start, date_end, date_end, date_end)

    months_ru = {1: "Январь", 2: "Февраль", 3: "Март", 4: "Апрель", 5: "Май", 6: "Июнь",
                 7: "Июль", 8: "Август", 9: "Сентябрь", 10: "Октябрь", 11: "Ноябрь", 12: "Декабрь"}
    month_name = months_ru.get(tmonth, f"{tmonth:02d}")

    # FIRM_ID по c.ID
    q_firm = """
        select e.FIRM_ID, f.SNAME from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e
                join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s
                group by e.ID, e.FIRM_ID ) as e
        join UOV_SELFSERVICE_PR_TRANS t on t.EMP_ID = e.ID
        join UOV_SELFSERVICE_HR_FIRM f on f.ID = e.FIRM_ID
        where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31'))
        group by e.FIRM_ID, f.SNAME
    """
    cursor.execute(q_firm, (card_id, *date_params))
    firm_row = cursor.fetchone()
    if not firm_row:
        raise Exception("Не удалось определить FIRM_ID для сотрудника в указанном периоде.")
    firm_id = firm_row[0]

    # ШАПКА по c.ID
    q_header = """
        select s.NAME as [NAME], ROUND(t.WAGE, 2), isnull(sum(yt.u21 + yt.u30), 0), ROUND(isnull(sum(yt.n200 + yt.n5100 - yt.u21 - yt.u30 - yt.u42 - yt.u99), 0), 2)
        from (select e.ID, e.FIRM_ID, e.CARD_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID
                where c.ID = %s and e.FIRM_ID=%s group by e.ID, e.FIRM_ID, e.CARD_ID ) as e 
        join UOV_SELFSERVICE_pr_trans t on t.EMP_ID = e.ID join UOV_SELFSERVICE_hr_syspay s on s.ID = t.SYSPAY_ID 
        join UOV_SELFSERVICE_sl_ytax yt on yt.CARD_ID = e.CARD_ID and yt.FIRM_ID = e.FIRM_ID
        where e.FIRM_ID = %s and yt.tmonth = %s and yt.tyear = %s
        and ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31'))
        and t.tp_abbr='CUR' group by s.NAME, t.WAGE, t.D_FROM order by t.D_FROM desc
    """
    cursor.execute(q_header, (card_id, firm_id, firm_id, tmonth, tyear, *date_params))
    h_row = cursor.fetchone()
    header_sys = str(h_row[0]) if h_row else "Неизвестная система"
    header_wage = float(h_row[1]) if h_row and h_row[1] else 0.0
    header_deduct = float(h_row[2]) if h_row and h_row[2] else 0.0
    header_base = float(h_row[3]) if h_row and h_row[3] else 0.0

    # НАЧИСЛЕНО по c.ID
    q_earn = """
        select p.NAME AS [NAME], ROUND(l.days, 1), ROUND(l.hours, 1), CAST(l.prc as INT), convert(varchar, i.D_FROM,104)+'-'+convert(varchar, i.D_TO,104), ROUND(l.summa, 2)
        from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e 
        join UOV_SELFSERVICE_sl_lic l on l.EMP_ID = e.ID join UOV_SELFSERVICE_sl_pay p on p.ID = l.PAY_ID join UOV_SELFSERVICE_pr_ill i on i.ID=l.ID_MAIN
        join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans t where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31')) group by EMP_ID) tr on tr.EMP_ID = e.ID
        where l.t_pay = 1 and l.pay_id not in (264,301,262) and l.n_dirm = 6 and l.cmonth = %s 
        UNION ALL 
        select max(p.NAME) AS [NAME], sum(l.days), ROUND(sum(l.hours), 1), CAST(l.prc as INT), (DateName(month, DateAdd(month, l.TMONTH, 0) - 1) +' '+ cast(l.TYEAR as varchar)), ROUND(isnull(sum(l.summa),0), 2)
        from(select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e 
        join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans t where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31')) group by EMP_ID) tr on tr.EMP_ID = e.ID
        join UOV_SELFSERVICE_sl_lic l on l.EMP_ID = e.ID join UOV_SELFSERVICE_sl_pay p on p.ID = l.PAY_ID
        where l.t_pay = 1 and l.pay_id not in (264,301,262) and l.n_dirm <> 6 and l.cmonth = %s 
        group by l.emp_id,l.pay_id,l.tmonth,l.prc, case l.PAY_ID when 17 then l.id else 0 end, l.TYEAR order by 6 DESC
    """
    cursor.execute(q_earn, (card_id, firm_id, *date_params, target_cmonth, card_id, firm_id, *date_params, target_cmonth))
    earnings_rows = cursor.fetchall()

    # УДЕРЖАНО по c.ID
    q_deduct = """
        select max(p.NAME) AS [NAME], CAST(l.prc as INT), ISNULL(DATENAME(month, DATEADD(month, l.tmonth, 0) - 1) + ' ' + CAST(NULLIF(l.TYEAR, 0) AS varchar), ''), ROUND(isnull(sum(l.summa),0), 2)
        from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e 
        JOIN UOV_SELFSERVICE_sl_lic l ON l.EMP_ID = e.ID JOIN UOV_SELFSERVICE_sl_pay p ON p.ID = l.PAY_ID
        join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans t where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31')) group by EMP_ID) tr on tr.EMP_ID = e.ID
        where l.t_pay=2 and l.pay_id not in (301,490) and l.pay_id not in (305, 308, 316, 328, 360, 364) and l.cmonth = %s 
        group by l.emp_id,l.pay_id,l.tmonth,l.prc, l.id, l.TYEAR order by 4 DESC
    """
    cursor.execute(q_deduct, (card_id, firm_id, *date_params, target_cmonth))
    deductions_rows = cursor.fetchall()

    # ДОЛГИ по c.ID
    q_debts = """
        select l.pay_id, ROUND(isnull(sum(l.summa),0), 2) from (select e.ID, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e
        join UOV_SELFSERVICE_sl_lic l on l.EMP_ID = e.id join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans t where ((t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO >= %s) or (t.D_FROM <= %s and t.D_TO = '1999-12-31')) group by EMP_ID) tr on tr.EMP_ID = e.ID
        where l.cmonth = %s and l.pay_id in (264, 301, 490) group by l.pay_id
    """
    cursor.execute(q_debts, (card_id, firm_id, *date_params, target_cmonth))
    debt_rows = cursor.fetchall()
    debt_comp_start, debt_emp_start, debt_emp_end = 0.0, 0.0, 0.0
    for r in debt_rows:
        if r[0] == 264: debt_comp_start = float(r[1])
        elif r[0] == 301: debt_emp_start = float(r[1])
        elif r[0] == 490: debt_emp_end = float(r[1])

    # НЕ ДЕНЕЖНЫЕ по c.ID
    q_noncash = """
        select t.NAME AS [NAME], (DateName(month, CAST(%s as date)) +' '+ DateName(YEAR, CAST(%s as date))), ROUND(isnull(p.summa, 0), 2)
        from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e 
        join UOV_SELFSERVICE_sl_profit p on p.EMP_ID = e.ID join UOV_SELFSERVICE_sl_tprofit t on t.ID  = p.TPROFIT_ID
        join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans tr where ((tr.D_FROM <= %s and tr.D_TO >= %s) or (tr.D_FROM <= %s and tr.D_TO >= %s) or (tr.D_FROM <= %s and tr.D_TO = '1999-12-31')) group by EMP_ID) tr2 on tr2.EMP_ID = e.ID
        where p.cmonth = %s and t.id != 9999
    """
    cursor.execute(q_noncash, (date_start, date_start, card_id, firm_id, *date_params, target_cmonth))
    noncash_rows = cursor.fetchall()

    # ВЫПЛАЧЕНО по c.ID
    q_payout = """
        select p.NAME AS [NAME], (DateName(month, DateAdd(month, l.TMONTH, 0) - 1) +' '+ cast(l.TYEAR as varchar)), ROUND(sum(isnull(l.summa, 0)), 2)  
        from (select e.id, e.FIRM_ID from UOV_SELFSERVICE_PR_EMP e join UOV_SELFSERVICE_PR_CARD c on c.ID=e.CARD_ID where c.ID = %s and e.FIRM_ID=%s group by e.ID, FIRM_ID ) as e 
        join UOV_SELFSERVICE_sl_lic l on l.EMP_ID = e.ID join UOV_SELFSERVICE_sl_pay p on p.ID =l.PAY_ID
        join (select MAX(id) as id, EMP_ID  from UOV_SELFSERVICE_pr_trans tr where ((tr.D_FROM <= %s and tr.D_TO >= %s) or (tr.D_FROM <= %s and tr.D_TO >= %s) or (tr.D_FROM <= %s and tr.D_TO = '1999-12-31')) group by EMP_ID) tr2 on tr2.EMP_ID = e.ID
        where l.t_pay = 2 and l.cmonth = %s and l.pay_id in (305, 308, 316, 328, 360, 364) group by p.NAME, l.TMONTH, l.TYEAR
    """
    cursor.execute(q_payout, (card_id, firm_id, *date_params, target_cmonth))
    payout_rows = cursor.fetchall()

    total_earned = sum(float(r[5]) for r in earnings_rows if r[5])
    total_withheld = sum(float(r[3]) for r in deductions_rows if r[3])
    total_noncash = sum(float(r[2]) for r in noncash_rows if r[2])
    total_payouts = sum(float(r[2]) for r in payout_rows if r[2])
    
    # Расчет долга по формуле СибЦема
    debt_comp_end = total_earned - total_withheld - total_payouts
    net_pay = total_earned - total_withheld

    response = f"💰 <b>Расчетный листок за {month_name} {tyear} г.</b>\n\n<b>1. Начислено</b>\n"
    for row in earnings_rows:
        time_spent = f" ({float(row[1]):g} дн. / {float(row[2]):g} ч.)" if (row[1] or row[2]) else ""
        response += f"🔹 {str(row[0]).strip()}{time_spent}: <b>{format_currency(row[5])} руб.</b>\n"
    response += f"<b>Всего начислено: {format_currency(total_earned)} руб.</b>\n\n<b>2. Удержано</b>\n"
    for row in deductions_rows:
        prc_str = f" ({int(row[1])}%)" if row[1] else ""
        response += f"🔹 {str(row[0]).strip()}{prc_str}: <b>{format_currency(row[3])} руб.</b>\n"
    response += f"<b>Всего удержано: {format_currency(total_withheld)} руб.</b>\n\n<b>3. Доходы в неденежной форме:</b> {format_currency(total_noncash)} руб.\n\n<b>4. Выплачено</b>\n"
    for row in payout_rows:
        response += f"🔹 {str(row[0]).strip()}: <b>{format_currency(row[2])} руб.</b>\n"
    response += f"<b>Всего выплачено: {format_currency(total_payouts)} руб.</b>\n\n<i>Долг за предприятием на конец месяца: {format_currency(debt_comp_end)} руб.</i>\n<i>Долг за работником на конец месяца: {format_currency(debt_emp_end)} руб.</i>\n\n<b>5. Выплачено денежными средствами: {format_currency(net_pay)} руб.</b>"

    pdf_path = create_payslip_pdf(
        month_name, tyear, header_sys, header_wage, header_deduct, header_base,
        earnings_rows, deductions_rows, noncash_rows, payout_rows,
        total_earned, total_withheld, total_noncash, total_payouts,
        debt_comp_start, debt_emp_start, debt_comp_end, debt_emp_end, net_pay
    )
    return response, pdf_path