import os
import sys
import unittest
from datetime import datetime, date

# Agregar el directorio raíz al path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

from src.services.report_606_service import Report606Service
from src.models.invoice import Invoice
from src.models.company import Company

class Test606Format(unittest.TestCase):
    """Pruebas específicas para el formato 606 de la DGII"""
    
    def setUp(self):
        """Configuración antes de cada prueba"""
        self.service = Report606Service()
        
        # Crear empresa de prueba
        self.test_company = Company(
            id=1,
            name="Empresa de Prueba S.R.L.",
            rnc="101-12345-6",
            address="Calle de Prueba #123",
            phone="809-555-0123",
            email="test@empresa.com",
            status="active"
        )
        
        # Crear factura de prueba
        self.test_invoice = Invoice(
            id=1,
            invoice_number="INV-20240801-TEST",
            ncf="B0100000001",
            ncf_modified="",
            supplier_name="Proveedor de Prueba S.A.",
            supplier_rnc="101-98765-4",
            supplier_id_type="RNC",
            invoice_date=date(2024, 8, 15),
            payment_date=date(2024, 8, 20),
            invoiced_amount=100000.00,
            itbis_invoiced=18000.00,
            itbis_retained=1000.00,
            itbis_perceived=0.00,
            income_retention=500.00,
            isr_perceived=0.00,
            selective_consumption_tax=0.00,
            other_taxes=0.00,
            legal_tip=0.00,
            expense_type="02",
            expense_description="Gastos por Trabajos, Suministros y Servicios",
            status="approved",
            company_id=1,
            created_by_user_id=1
        )
    
    def test_format_date_valid(self):
        """Prueba de formateo de fechas válidas"""
        # Fecha como objeto date
        test_date = date(2024, 8, 15)
        formatted = self.service._format_date(test_date)
        self.assertEqual(formatted, "20240815")
        
        # Fecha como string
        formatted = self.service._format_date("2024-08-15")
        self.assertEqual(formatted, "20240815")
    
    def test_format_date_invalid(self):
        """Prueba de formateo de fechas inválidas"""
        # Fecha None
        formatted = self.service._format_date(None)
        self.assertEqual(formatted, "")
        
        # String inválido
        formatted = self.service._format_date("fecha-invalida")
        self.assertEqual(formatted, "")
    
    def test_format_amount_valid(self):
        """Prueba de formateo de montos válidos"""
        # Monto normal
        formatted = self.service._format_amount(1000.50)
        self.assertEqual(formatted, "100050")  # 1000.50 * 100 = 100050 centavos
        
        # Monto con muchos decimales
        formatted = self.service._format_amount(1000.567)
        self.assertEqual(formatted, "100057")  # Redondeado
        
        # Monto cero
        formatted = self.service._format_amount(0)
        self.assertEqual(formatted, "0")
    
    def test_format_amount_invalid(self):
        """Prueba de formateo de montos inválidos"""
        # Monto None
        formatted = self.service._format_amount(None)
        self.assertEqual(formatted, "0")
    
    def test_generate_header_line(self):
        """Prueba de generación de línea de encabezado"""
        header = self.service._generate_header_line(self.test_company, 2024, 8, 5)
        expected = "606|101-12345-6|202408|5"
        self.assertEqual(header, expected)
    
    def test_generate_detail_line(self):
        """Prueba de generación de línea de detalle"""
        detail = self.service._generate_detail_line(self.test_invoice)
        
        # Verificar que empiece con 607
        self.assertTrue(detail.startswith("607|"))
        
        # Dividir campos y verificar algunos valores clave
        fields = detail.split("|")
        self.assertEqual(fields[0], "607")  # Tipo de registro
        self.assertEqual(fields[1], "101-98765-4")  # RNC proveedor
        self.assertEqual(fields[2], "1")  # Tipo ID (RNC)
        self.assertEqual(fields[3], "B0100000001")  # NCF
        self.assertEqual(fields[5], "20240815")  # Fecha factura
        self.assertEqual(fields[6], "20240820")  # Fecha pago
        self.assertEqual(fields[7], "10000000")  # Monto facturado (en centavos)
        self.assertEqual(fields[8], "1800000")  # ITBIS facturado (en centavos)
        self.assertEqual(fields[9], "100000")  # ITBIS retenido (en centavos)
        self.assertEqual(fields[16], "02")  # Tipo de gasto
    
    def test_generate_606_content_structure(self):
        """Prueba de estructura del contenido 606"""
        invoices = [self.test_invoice]
        content = self.service._generate_606_content(self.test_company, invoices, 2024, 8)
        
        lines = content.split("\n")
        self.assertEqual(len(lines), 2)  # 1 encabezado + 1 detalle
        
        # Verificar encabezado
        header = lines[0]
        self.assertTrue(header.startswith("606|"))
        self.assertIn("101-12345-6", header)
        self.assertIn("202408", header)
        self.assertIn("1", header)  # 1 registro
        
        # Verificar detalle
        detail = lines[1]
        self.assertTrue(detail.startswith("607|"))
        self.assertIn("101-98765-4", detail)
        self.assertIn("B0100000001", detail)
    
    def test_calculate_totals(self):
        """Prueba de cálculo de totales"""
        invoices = [self.test_invoice]
        totals = self.service._calculate_totals(invoices)
        
        self.assertEqual(totals['total_amount'], 100000.00)
        self.assertEqual(totals['total_itbis'], 18000.00)
    
    def test_expense_type_summary(self):
        """Prueba de resumen por tipo de gasto"""
        invoices = [self.test_invoice]
        summary = self.service._get_expense_type_summary(invoices)
        
        self.assertEqual(len(summary), 1)
        self.assertEqual(summary[0]['type'], '02')
        self.assertEqual(summary[0]['count'], 1)
        self.assertEqual(summary[0]['amount'], 100000.00)
    
    def test_supplier_summary(self):
        """Prueba de resumen por proveedor"""
        invoices = [self.test_invoice]
        summary = self.service._get_supplier_summary(invoices)
        
        self.assertEqual(len(summary), 1)
        self.assertEqual(summary[0]['supplier_name'], 'Proveedor de Prueba S.A.')
        self.assertEqual(summary[0]['supplier_rnc'], '101-98765-4')
        self.assertEqual(summary[0]['count'], 1)
        self.assertEqual(summary[0]['amount'], 100000.00)
    
    def test_606_format_compliance(self):
        """Prueba de cumplimiento con formato 606 oficial"""
        # Crear múltiples facturas para prueba más completa
        invoices = [
            self.test_invoice,
            Invoice(
                id=2,
                invoice_number="INV-20240802-TEST2",
                ncf="B0100000002",
                supplier_name="Otro Proveedor EIRL",
                supplier_rnc="130-11111-1",
                supplier_id_type="RNC",
                invoice_date=date(2024, 8, 20),
                payment_date=date(2024, 8, 25),
                invoiced_amount=50000.00,
                itbis_invoiced=9000.00,
                itbis_retained=0.00,
                expense_type="03",
                status="approved",
                company_id=1
            )
        ]
        
        content = self.service._generate_606_content(self.test_company, invoices, 2024, 8)
        lines = content.split("\n")
        
        # Verificar cantidad de líneas
        self.assertEqual(len(lines), 3)  # 1 encabezado + 2 detalles
        
        # Verificar que el encabezado indica 2 registros
        header_fields = lines[0].split("|")
        self.assertEqual(header_fields[3], "2")
        
        # Verificar que todas las líneas de detalle empiecen con 607
        for i in range(1, len(lines)):
            self.assertTrue(lines[i].startswith("607|"))
        
        # Verificar que cada línea de detalle tenga 17 campos
        for i in range(1, len(lines)):
            fields = lines[i].split("|")
            self.assertEqual(len(fields), 17)
    
    def test_edge_cases(self):
        """Prueba de casos extremos"""
        # Factura con valores None
        invoice_with_nulls = Invoice(
            id=3,
            invoice_number="INV-NULL-TEST",
            ncf="B0100000003",
            supplier_name="Proveedor Sin Datos",
            supplier_rnc="101-00000-0",
            invoice_date=date(2024, 8, 25),
            payment_date=None,  # Sin fecha de pago
            invoiced_amount=1000.00,
            itbis_invoiced=None,  # Sin ITBIS
            itbis_retained=None,
            expense_type="06",
            status="approved",
            company_id=1
        )
        
        detail = self.service._generate_detail_line(invoice_with_nulls)
        fields = detail.split("|")
        
        # Verificar que los campos None se manejen correctamente
        self.assertEqual(fields[6], "")  # Fecha de pago vacía
        self.assertEqual(fields[8], "0")  # ITBIS facturado = 0
        self.assertEqual(fields[9], "0")  # ITBIS retenido = 0
    
    def test_month_edge_cases(self):
        """Prueba de casos extremos de meses"""
        # Enero
        header_jan = self.service._generate_header_line(self.test_company, 2024, 1, 1)
        self.assertIn("202401", header_jan)
        
        # Diciembre
        header_dec = self.service._generate_header_line(self.test_company, 2024, 12, 1)
        self.assertIn("202412", header_dec)

def run_606_tests():
    """Ejecuta las pruebas específicas del formato 606"""
    print("🧪 Iniciando pruebas del formato 606...")
    
    # Crear suite de pruebas
    loader = unittest.TestLoader()
    suite = loader.loadTestsFromTestCase(Test606Format)
    
    # Ejecutar pruebas
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)
    
    # Resumen de resultados
    print(f"\n📊 Resumen de pruebas del formato 606:")
    print(f"   - Ejecutadas: {result.testsRun}")
    print(f"   - Exitosas: {result.testsRun - len(result.failures) - len(result.errors)}")
    print(f"   - Fallidas: {len(result.failures)}")
    print(f"   - Errores: {len(result.errors)}")
    
    if result.failures:
        print(f"\n❌ Pruebas fallidas:")
        for test, traceback in result.failures:
            print(f"   - {test}")
    
    if result.errors:
        print(f"\n💥 Errores en pruebas:")
        for test, traceback in result.errors:
            print(f"   - {test}")
    
    success = len(result.failures) == 0 and len(result.errors) == 0
    if success:
        print(f"\n✅ Todas las pruebas del formato 606 pasaron!")
    else:
        print(f"\n❌ Algunas pruebas del formato 606 fallaron.")
    
    return success

if __name__ == '__main__':
    run_606_tests()

