"""
Order Generation Service for Time Tracking Module
==================================================

Aggreger godkendte tidsregistreringer til customer orders.
Beregn totals, moms, og opret order lines.
"""

import logging
from typing import List, Optional
from decimal import Decimal
from datetime import date

from fastapi import HTTPException
from app.core.config import settings
from app.core.database import execute_query, execute_insert, execute_update, execute_query_single
from app.timetracking.backend.models import (
    TModuleOrder,
    TModuleOrderWithLines,
    TModuleOrderLine,
    TModuleOrderCreate,
    TModuleOrderLineCreate
)
from app.timetracking.backend.audit import audit

logger = logging.getLogger(__name__)


class OrderService:
    """Service for generating orders from approved time entries"""
    
    @staticmethod
    def _get_hourly_rate(customer_id: int, hub_customer_id: Optional[int]) -> Decimal:
        """
        Hent timepris for kunde.
        
        Prioritet:
        1. customer_id (tmodule_customers.hourly_rate)
        2. hub_customer_id (customers.hourly_rate) 
        3. Default fra settings
        """
        try:
            # Check module customer
            query = "SELECT hourly_rate FROM tmodule_customers WHERE id = %s"
            result = execute_query(query, (customer_id,))
            
            if result and result[0].get('hourly_rate'):
                rate = result[0]['hourly_rate']
                logger.info(f"✅ Using tmodule customer rate: {rate} DKK")
                return Decimal(str(rate))
            
            # Hub customers table doesn't have hourly_rate column
            # Skip that check and go straight to default
            
            # Fallback to default
            default_rate = Decimal(str(settings.TIMETRACKING_DEFAULT_HOURLY_RATE))
            logger.warning(f"⚠️ No customer rate found, using default: {default_rate} DKK")
            return default_rate
        
        except Exception as e:
            logger.error(f"❌ Error getting hourly rate: {e}")
            # Safe fallback
            return Decimal(str(settings.TIMETRACKING_DEFAULT_HOURLY_RATE))
    
    @staticmethod
    def generate_order_for_customer(
        customer_id: int,
        user_id: Optional[int] = None
    ) -> TModuleOrderWithLines:
        """
        Generer ordre for alle godkendte tider for en kunde.
        
        Args:
            customer_id: ID fra tmodule_customers
            user_id: ID på brugeren der opretter
            
        Returns:
            Order med lines
        """
        try:
            # Hent customer info
            customer = execute_query_single(
                "SELECT * FROM tmodule_customers WHERE id = %s",
                (customer_id,))
            
            if not customer:
                raise HTTPException(status_code=404, detail=f"Customer {customer_id} not found in tmodule_customers")
            
            # Debug log
            logger.info(f"✅ Found customer: {customer.get('name') if isinstance(customer, dict) else type(customer)}")
            
            # Hent godkendte tider for kunden med case og contact detaljer (Supports both vTiger Cases and Hub Sags)
            query = """
                SELECT t.*, 
                       COALESCE(
                           NULLIF(TRIM(c.title), ''),
                           NULLIF(TRIM(c.vtiger_data->>'ticket_title'), ''),
                           NULLIF(TRIM(s.titel), ''),
                           'Ingen titel'
                       ) as case_title,
                       COALESCE(c.vtiger_id, CONCAT('SAG-', s.id)) as case_vtiger_id,
                       COALESCE(
                           c.vtiger_data->>'case_no', 
                           c.vtiger_data->>'ticket_no',
                           CONCAT('SAG-', s.id)
                       ) as case_number,
                       c.vtiger_data->>'ticket_title' as vtiger_title,
                       COALESCE(c.priority, 'Normal') as case_priority,
                       COALESCE(c.status, s.status) as case_status,
                       COALESCE(c.module_type, 'sag') as case_type,
                       CONCAT(cont.first_name, ' ', cont.last_name) as contact_name
                FROM tmodule_times t
                LEFT JOIN tmodule_cases c ON t.case_id = c.id
                LEFT JOIN sag_sager s ON t.sag_id = s.id
                LEFT JOIN contacts cont ON cont.vtiger_id = c.vtiger_data->>'contact_id'
                WHERE t.customer_id = %s 
                  AND t.status = 'approved'
                  AND t.billable = true
                ORDER BY COALESCE(c.id, s.id), t.worked_date
            """
            approved_times = execute_query(query, (customer_id,))
            
            if not approved_times:
                raise HTTPException(
                    status_code=400,
                    detail="No approved billable time entries found for customer"
                )
            
            logger.info(f"📊 Found {len(approved_times)} approved time entries")
            
            # Get hourly rate
            hourly_rate = OrderService._get_hourly_rate(
                customer_id,
                customer.get('hub_customer_id')
            )
            
            # Group by case og gem ekstra metadata
            case_groups = {}
            for time_entry in approved_times:
                # Use case_number as unique key to prevent collision between Cases and Sags
                case_key = time_entry.get('case_number')
                if not case_key:
                    # Fallback to ID if no number (should not happen with updated query)
                    case_key = str(time_entry.get('case_id') or time_entry.get('sag_id'))

                if case_key not in case_groups:
                    # Prioriter case title fra vTiger (c.title), fallback til vtiger_data title
                    case_title = time_entry.get('case_title') or time_entry.get('vtiger_title')
                    case_groups[case_key] = {
                        'case_id': time_entry.get('case_id'),
                        'sag_id': time_entry.get('sag_id'),
                        'case_vtiger_id': time_entry.get('case_vtiger_id'),
                        'case_number': time_entry.get('case_number'),  # Fra vtiger_data
                        'case_title': case_title,  # Case titel fra vTiger
                        'case_priority': time_entry.get('case_priority'),  # Prioritet
                        'case_status': time_entry.get('case_status'),  # Status
                        'case_type': time_entry.get('case_type'),  # Brand/Type (module_type)
                        'contact_name': time_entry.get('contact_name'),
                        'worked_date': time_entry.get('worked_date'),  # Seneste dato
                        'is_travel': False,  # Marker hvis nogen entry er rejse
                        'entries': [],
                        'descriptions': []  # Samle alle beskrivelser
                    }
                case_groups[case_key]['entries'].append(time_entry)
                # Opdater til seneste dato
                if time_entry.get('worked_date'):
                    if not case_groups[case_key]['worked_date'] or time_entry['worked_date'] > case_groups[case_key]['worked_date']:
                        case_groups[case_key]['worked_date'] = time_entry['worked_date']
                # Marker som rejse hvis nogen entry er rejse
                if time_entry.get('is_travel'):
                    case_groups[case_key]['is_travel'] = True
                # Tilføj beskrivelse hvis den ikke er tom
                if time_entry.get('description') and time_entry['description'].strip():
                    case_groups[case_key]['descriptions'].append(time_entry['description'].strip())
            
            # Build order lines
            order_lines = []
            line_number = 1
            total_hours = Decimal('0')
            
            for case_id, group in case_groups.items():
                # Sum hours for this case
                case_hours = sum(
                    Decimal(str(entry['approved_hours'])) 
                    for entry in group['entries']
                )
                
                # Check if any entries were rounded
                original_hours = sum(
                    Decimal(str(entry['original_hours']))
                    for entry in group['entries']
                )
                was_rounded = (case_hours != original_hours)
                
                # Extract case number ONLY from vtiger_data case_no field
                # NEVER parse from vtiger_id as they don't match (39x40366 vs CC2141)
                case_number = group.get('case_number') or ""
                
                # Brug case titel fra vTiger 
                case_title = group.get('case_title') or ""
                
                # Hvis case titel er generisk placeholder, brug contact + dato (IKKE descriptions)
                # Descriptions bruges kun i ordre notes, ikke som titel
                if not case_title or case_title.strip() == "" or case_title.lower() in ['none', 'ingen beskrivelse', 'ingen titel', 'no title']:
                    if group.get('contact_name'):
                        # Brug contact navn og dato
                        date_str = group.get('worked_date', '').strftime('%d.%m.%Y') if group.get('worked_date') else ''
                        case_title = f"Support til {group['contact_name']}"
                        if date_str:
                            case_title += f" - {date_str}"
                    else:
                        # Sidste fallback hvis intet andet
                        case_title = "Support arbejde"
                
                # Build description med case nummer, titel, dato, type, prioritet
                description_parts = []
                
                # Case nummer og titel
                if case_number:
                    description_parts.append(f"{case_number} - {case_title}")
                else:
                    description_parts.append(case_title)
                
                # Dato
                if group.get('worked_date'):
                    date_str = group['worked_date'].strftime('%d.%m.%Y')
                    description_parts.append(f"Dato: {date_str}")
                
                # Brand/Type (module_type)
                if group.get('case_type'):
                    description_parts.append(f"Type: {group['case_type']}")
                
                # Prioritet
                if group.get('case_priority'):
                    description_parts.append(f"Prioritet: {group['case_priority']}")
                
                # Join all parts with newlines for multi-line description
                description = "\n".join(description_parts)
                
                # Calculate line total
                line_total = case_hours * hourly_rate
                
                # Collect time entry IDs
                time_entry_ids = [entry['id'] for entry in group['entries']]
                
                order_lines.append(TModuleOrderLineCreate(
                    line_number=line_number,
                    description=description,
                    quantity=case_hours,
                    unit_price=hourly_rate,
                    line_total=line_total,
                    case_id=group.get('case_id'),
                    sag_id=group.get('sag_id'),
                    time_entry_ids=time_entry_ids,
                    case_contact=group.get('contact_name'),
                    time_date=group.get('worked_date'),
                    is_travel=group.get('is_travel', False)
                ))
                
                total_hours += case_hours
                line_number += 1
            
            # Calculate totals
            subtotal = total_hours * hourly_rate
            vat_rate = Decimal('25.00')  # Danish VAT
            vat_amount = (subtotal * vat_rate / Decimal('100')).quantize(Decimal('0.01'))
            total_amount = subtotal + vat_amount
            
            logger.info(f"💰 Order totals: {total_hours}h × {hourly_rate} = {subtotal} + {vat_amount} moms = {total_amount} DKK")
            
            # Create order
            order_id = execute_insert(
                """INSERT INTO tmodule_orders 
                   (customer_id, hub_customer_id, order_date, total_hours, hourly_rate,
                    subtotal, vat_rate, vat_amount, total_amount, status, created_by)
                   VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, 'draft', %s)
                   RETURNING id""",
                (
                    customer_id,
                    customer.get('hub_customer_id'),
                    date.today(),
                    total_hours,
                    hourly_rate,
                    subtotal,
                    vat_rate,
                    vat_amount,
                    total_amount,
                    user_id
                )
            )
            
            logger.info(f"✅ Created order {order_id}")
            
            # Create order lines
            created_lines = []
            for line in order_lines:
                line_id = execute_insert(
                    """INSERT INTO tmodule_order_lines
                       (order_id, case_id, sag_id, line_number, description, quantity, unit_price,
                        line_total, time_entry_ids, case_contact, time_date, is_travel)
                       VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
                       RETURNING id""",
                    (
                        order_id,
                        line.case_id,
                        line.sag_id,
                        line.line_number,
                        line.description,
                        line.quantity,
                        line.unit_price,
                        line.line_total,
                        line.time_entry_ids,
                        line.case_contact,
                        line.time_date,
                        line.is_travel
                    )
                )
                created_lines.append(line_id)
            
            logger.info(f"✅ Created {len(created_lines)} order lines")
            
            # NOTE: Time entries remain 'approved' status until exported to e-conomic
            # They will be updated to 'billed' with billed_via_thehub_id in economic_export.py
            
            # Log order creation
            audit.log_order_created(
                order_id=order_id,
                customer_id=customer_id,
                total_hours=float(total_hours),
                total_amount=float(total_amount),
                line_count=len(order_lines),
                user_id=user_id
            )
            
            # Return full order with lines
            return OrderService.get_order_with_lines(order_id)
        
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"❌ Error generating order: {e}")
            raise HTTPException(status_code=500, detail=str(e))
    
    @staticmethod
    def get_order_with_lines(order_id: int) -> TModuleOrderWithLines:
        """Hent ordre med linjer"""
        try:
            # Get order with customer name
            order_query = """
                SELECT o.*, c.name as customer_name
                FROM tmodule_orders o
                LEFT JOIN tmodule_customers c ON o.customer_id = c.id
                WHERE o.id = %s
            """
            order = execute_query_single(order_query, (order_id,))
            
            if not order:
                raise HTTPException(status_code=404, detail="Order not found")
            
            # Get lines with additional context (contact, date)
            lines_query = """
                SELECT ol.*,
                       STRING_AGG(DISTINCT CONCAT(cont.first_name, ' ', cont.last_name), ', ') as case_contact,
                       MIN(t.worked_date) as time_date
                FROM tmodule_order_lines ol
                LEFT JOIN tmodule_times t ON t.id = ANY(ol.time_entry_ids)
                LEFT JOIN tmodule_cases c ON c.id = ol.case_id
                LEFT JOIN contacts cont ON cont.vtiger_id = c.vtiger_data->>'contact_id'
                WHERE ol.order_id = %s 
                GROUP BY ol.id, ol.order_id, ol.case_id, ol.line_number, ol.description, 
                         ol.quantity, ol.unit_price, ol.line_total, ol.time_entry_ids, 
                         ol.product_number, ol.account_number, ol.created_at
                ORDER BY ol.line_number
            """
            lines = execute_query(lines_query, (order_id,))
            
            return TModuleOrderWithLines(
                **order,
                lines=[TModuleOrderLine(**line) for line in lines]
            )
        
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"❌ Error getting order: {e}")
            raise HTTPException(status_code=500, detail=str(e))
    
    @staticmethod
    def list_orders(
        customer_id: Optional[int] = None,
        status: Optional[str] = None,
        limit: int = 100
    ) -> List[TModuleOrder]:
        """List orders med filtrering"""
        try:
            conditions = []
            params = []
            
            if customer_id:
                conditions.append("o.customer_id = %s")
                params.append(customer_id)
            
            if status:
                conditions.append("o.status = %s")
                params.append(status)
            
            where_clause = " WHERE " + " AND ".join(conditions) if conditions else ""
            
            query = f"""
                SELECT o.*, 
                       c.name as customer_name,
                       (SELECT COUNT(*) FROM tmodule_order_lines WHERE order_id = o.id) as line_count
                FROM tmodule_orders o
                LEFT JOIN tmodule_customers c ON o.customer_id = c.id
                {where_clause}
                ORDER BY o.order_date DESC, o.id DESC
                LIMIT %s
            """
            params.append(limit)
            
            orders = execute_query(query, params if params else None)
            
            return [TModuleOrder(**order) for order in orders]
        
        except Exception as e:
            logger.error(f"❌ Error listing orders: {e}")
            raise HTTPException(status_code=500, detail=str(e))
    
    @staticmethod
    def cancel_order(
        order_id: int,
        reason: Optional[str] = None,
        user_id: Optional[int] = None
    ) -> TModuleOrder:
        """Annuller en ordre"""
        try:
            # Check order exists and is not exported
            order_result = execute_query(
                "SELECT * FROM tmodule_orders WHERE id = %s",
                (order_id,))
            
            if not order_result:
                raise HTTPException(status_code=404, detail="Order not found")
            
            order = order_result[0]
            
            if order['status'] == 'cancelled':
                raise HTTPException(status_code=400, detail="Order already cancelled")
            
            if order['status'] in ('exported', 'posted'):
                raise HTTPException(
                    status_code=400,
                    detail="Kan ikke annullere bogført ordre. Ordren er overført til e-conomic."
                )
            
            # Update status
            execute_update(
                "UPDATE tmodule_orders SET status = 'cancelled', notes = %s WHERE id = %s",
                (reason, order_id)
            )
            
            # Reset time entries back to approved
            lines = execute_query(
                "SELECT time_entry_ids FROM tmodule_order_lines WHERE order_id = %s",
                (order_id,)
            )
            
            all_time_ids = []
            for line in lines:
                if line.get('time_entry_ids'):
                    all_time_ids.extend(line['time_entry_ids'])
            
            if all_time_ids:
                placeholders = ','.join(['%s'] * len(all_time_ids))
                execute_update(
                    f"UPDATE tmodule_times SET status = 'approved' WHERE id IN ({placeholders})",
                    all_time_ids
                )
            
            # Log cancellation
            audit.log_order_cancelled(
                order_id=order_id,
                reason=reason,
                user_id=user_id
            )
            
            logger.info(f"❌ Cancelled order {order_id}")
            
            # Return updated order
            updated = execute_query(
                "SELECT * FROM tmodule_orders WHERE id = %s",
                (order_id,))
            
            return TModuleOrder(**updated[0])
        
        except HTTPException:
            raise
        except Exception as e:
            logger.error(f"❌ Error cancelling order: {e}")
            raise HTTPException(status_code=500, detail=str(e))


# Singleton instance
order_service = OrderService()
