# Copyright (c) 2025, Jey Soft and contributors
# For license information, please see license.txt

import frappe
from frappe.model.document import Document
from frappe.utils import flt, getdate

from taxes_az.taxes_az.report.employee_payroll_register.employee_payroll_register import (
	DEDUCTION_TYPES,
	EARNING_TYPES,
	get_employee_doj_map,
	get_salary_slip_details,
	get_salary_slips,
)

QUARTER_DATE_RANGES = {
	"1. Rüb": ("01-01", "03-31"),
	"2. Rüb": ("04-01", "06-30"),
	"3. Rüb": ("07-01", "09-30"),
	"4. Rüb": ("10-01", "12-31"),
}

# Scrubbed keys for insurance formula calculation
_DSMF_ISCI = frappe.scrub("DSMF (işçi)")
_DSMF_SIRKET = frappe.scrub("DSMF (şirkət)")
_ISSIZLIK_ISCI = frappe.scrub("İşsizlikdən sığorta haqqı (işçi 0,5%)")
_ISSIZLIK_SIRKET = frappe.scrub("İşsizlikdən sığorta haqqı (şirkət 0,5%)")
_ITS_ISCI = frappe.scrub("İcbari tibbi sığorta (işçi 2%)")
_ITS_SIRKET = frappe.scrub("İcbari tibbi sığorta (şirkət 2%)")
_KOMPENSASIYA = frappe.scrub("Məzuniyyət Kompensasiyası")


class Singledeclarationrelatedtosalariedandnonsalariedwork(Document):
	pass


@frappe.whitelist()
def get_company_defaults(company):
	"""Fetch Company fields with Unicode names that can't go through client-side get_value."""
	doc = frappe.get_doc("Company", company)
	return {
		"mdssüzrə": doc.get("mdssüzrə") or "",
		"icbaritibbisığortaüzrə": doc.get("icbaritibbisığortaüzrə") or "",
		"işsizlikdənsığortaüzrə": doc.get("işsizlikdənsığortaüzrə") or "",
		"main_activity": doc.get("main_activity") or "",
	}


@frappe.whitelist()
def populate_declaration_tables(company, year, quarter):
	"""Populate child tables from payroll and absence data.

	Returns dict with data for each child table.
	"""
	try:
		year = int(year)
		if quarter not in QUARTER_DATE_RANGES:
			return {"success": False, "error": f"Invalid quarter: {quarter}"}

		start_suffix, end_suffix = QUARTER_DATE_RANGES[quarter]
		from_date = f"{year}-{start_suffix}"
		to_date = f"{year}-{end_suffix}"

		# Fetch payroll data once, build hissə_1 and hissə_2 from it
		payroll = fetch_payroll_data(company, from_date, to_date)
		hisse_1_data = build_hisse_1(payroll)
		hisse_2_data = build_hisse_2(payroll)
		hisse_3_data = get_absence_data(company, from_date, to_date)

		return {
			"success": True,
			"hisse_1_data": hisse_1_data,
			"hisse_2_data": hisse_2_data,
			"hisse_3_data": hisse_3_data,
		}

	except Exception as e:
		frappe.log_error(
			f"Error in populate_declaration_tables: {str(e)}",
			"Single Declaration",
		)
		return {"success": False, "error": str(e)}


def fetch_payroll_data(company, from_date, to_date):
	"""Fetch and aggregate salary slip data per employee. Shared by hissə_1 and hissə_2."""
	import erpnext

	company_currency = erpnext.get_company_currency(company)
	currency = "AZN"

	filters = {
		"company": company,
		"from_date": from_date,
		"to_date": to_date,
		"currency": currency,
		"docstatus": "Submitted",
	}

	salary_slips = get_salary_slips(filters, company_currency)
	if not salary_slips:
		return {"employee_map": {}, "fin_map": {}, "doj_map": {}}

	ss_earning_map = get_salary_slip_details(salary_slips, currency, company_currency, "earnings")
	ss_ded_map = get_salary_slip_details(salary_slips, currency, company_currency, "deductions")
	doj_map = get_employee_doj_map()

	all_scrubbed_keys = [frappe.scrub(e) for e in EARNING_TYPES] + [frappe.scrub(d) for d in DEDUCTION_TYPES]
	sum_fields = ["gross_pay", "total_deduction", "net_pay"] + all_scrubbed_keys

	employee_map = {}

	for ss in salary_slips:
		emp = ss.employee

		if emp not in employee_map:
			employee_map[emp] = {
				"employee": emp,
				"employee_name": ss.employee_name,
			}
			for field in sum_fields:
				employee_map[emp][field] = 0.0

		agg = employee_map[emp]

		for e in EARNING_TYPES:
			agg[frappe.scrub(e)] += flt(ss_earning_map.get(ss.name, {}).get(e, 0))

		if currency == company_currency:
			agg["gross_pay"] += flt(ss.gross_pay) * flt(ss.exchange_rate)
		else:
			agg["gross_pay"] += flt(ss.gross_pay)

		for d in DEDUCTION_TYPES:
			agg[frappe.scrub(d)] += flt(ss_ded_map.get(ss.name, {}).get(d, 0))

		if currency == company_currency:
			agg["total_deduction"] += flt(ss.total_deduction) * flt(ss.exchange_rate)
			agg["net_pay"] += flt(ss.net_pay) * flt(ss.exchange_rate)
		else:
			agg["total_deduction"] += flt(ss.total_deduction)
			agg["net_pay"] += flt(ss.net_pay)

	# Get FIN (passport_number) from Employee doctype
	employee_ids = list(employee_map.keys())
	fin_map = {}
	if employee_ids:
		fin_data = frappe.get_all("Employee", filters={"name": ["in", employee_ids]}, fields=["name", "passport_number"])
		fin_map = {d.name: d.passport_number for d in fin_data}

	return {"employee_map": employee_map, "fin_map": fin_map, "doj_map": doj_map}


def build_hisse_1(payroll):
	"""Build hissə_1 rows from aggregated payroll data."""
	employee_map = payroll["employee_map"]
	fin_map = payroll["fin_map"]

	result = []
	for agg in employee_map.values():
		child_row = {
			"soyadadataadı": agg["employee_name"],
			"fin": fin_map.get(agg["employee"], ""),
			"gəlirlərcəmi": agg["gross_pay"],
			# vergiməbləği intentionally not filled
			"hesablanmışmdsshaqqı": flt(agg.get(_DSMF_ISCI, 0)) + flt(agg.get(_DSMF_SIRKET, 0)),
			"hesablanmışişsizlikdənsığortahaqqı": flt(agg.get(_ISSIZLIK_ISCI, 0)) + flt(agg.get(_ISSIZLIK_SIRKET, 0)),
			"hesablanmışicbaritibbisığortahaqqı": flt(agg.get(_ITS_ISCI, 0)) + flt(agg.get(_ITS_SIRKET, 0)),
		}
		result.append(child_row)

	result.sort(key=lambda x: x.get("soyadadataadı", ""))
	return result


def build_hisse_2(payroll):
	"""Build hissə_2 rows from aggregated payroll data. Only employees with compensation."""
	employee_map = payroll["employee_map"]
	fin_map = payroll["fin_map"]
	doj_map = payroll["doj_map"]

	result = []
	for agg in employee_map.values():
		compensation = flt(agg.get(_KOMPENSASIYA, 0))
		if not compensation:
			continue

		emp = agg["employee"]
		doj = doj_map.get(emp)
		doj_year = str(getdate(doj).year) if doj else ""

		child_row = {
			"işçininsığortaolunanınsoyadıadıatasınınadı": agg["employee_name"],
			"fin": fin_map.get(emp, ""),
			"il": doj_year,
			"kompensasiyaməbləği": compensation,
		}
		result.append(child_row)

	result.sort(key=lambda x: x.get("işçininsığortaolunanınsoyadıadıatasınınadı", ""))
	return result


def get_absence_data(company, from_date, to_date):
	"""Fetch absence data from Monthly Absence Report for hissə_3."""
	from taxes_az.taxes_az.report.monthly_absence_report.monthly_absence_report import get_data

	filters = {
		"company": company,
		"from_date": from_date,
		"to_date": to_date,
	}

	data = get_data(filters)
	if not data:
		return []

	result = []
	for row in data:
		name_parts = [row.get("last_name", ""), row.get("first_name", "")]
		full_name = " ".join(p for p in name_parts if p)

		child_row = {
			"soyadadataadı": full_name,
			"fin": row.get("fin", ""),
			"işçininişləmədiyiişgünlərininsəbəbi": row.get("absent_reason", ""),
			"işçininişləmədiyiişgünlərininsayı": row.get("days_absent", 0),
		}
		result.append(child_row)

	return result
