#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Smart Save Service für Intelectra WebShop
Speichert nur echte Änderungen - keine DELETE * mehr!
"""

import json
import sys
import pymysql
import logging
from configparser import ConfigParser
import os
from datetime import datetime

# Logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler('/var/www/vhosts/intelectra.de/httpdocs/logs/item_save_service.log'),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger('item_save_service')

class ItemSaveService:
    """Intelligenter Save-Service mit Change Detection"""
    
    def __init__(self):
        self.conn = self._connect_db()
        self.cursor = self.conn.cursor(pymysql.cursors.DictCursor)
        
    def _connect_db(self):
        """DB-Connection aus config.ini"""
        config_file = os.path.join(os.path.dirname(__file__), 'db_config.ini')
        config = ConfigParser()
        config.read(config_file)
        
        return pymysql.connect(
            host=config.get('database', 'host', fallback='localhost'),
            user=config.get('database', 'user', fallback='tbapy'),
            password=config.get('database', 'password', fallback='9%%0H32ryj_N9%%0H32ryj'),
            database=config.get('database', 'database', fallback='webshop-sql'),
            charset='utf8mb4',
            cursorclass=pymysql.cursors.DictCursor
        )
    
    def save_alternative_items(self, item_id, new_items):
        """
        Speichert Alternativartikel - NUR Änderungen!
        Type 3 = Alternativartikel
        """
        try:
            # 1. Aktuelle Items laden
            self.cursor.execute(
                "SELECT item_child_id FROM item_item_assign WHERE item_parent_id = %s AND type = 3 ORDER BY position",
                (item_id,)
            )
            current_items = [row['item_child_id'] for row in self.cursor.fetchall()]
            
            # 2. Änderungen erkennen
            new_items = [int(x) for x in new_items if x]  # Clean input
            
            to_delete = set(current_items) - set(new_items)
            to_add = set(new_items) - set(current_items)
            
            # Reihenfolge geändert?
            order_changed = (current_items != new_items) and not to_delete and not to_add
            
            changes_made = False
            
            # 3. Nur löschen was weg muss
            if to_delete:
                placeholders = ','.join(['%s'] * len(to_delete))
                self.cursor.execute(
                    f"DELETE FROM item_item_assign WHERE item_parent_id = %s AND item_child_id IN ({placeholders}) AND type = 3",
                    [item_id] + list(to_delete)
                )
                logger.info(f"Deleted {len(to_delete)} alternative items from item {item_id}")
                changes_made = True
            
            # 4. Nur hinzufügen was neu ist
            if to_add:
                # Position berechnen - bei erster Zuweisung start bei 1
                if not current_items:
                    start_pos = 1
                else:
                    start_pos = len(current_items) - len(to_delete) + 1
                
                values = []
                for idx, child_id in enumerate(to_add):
                    values.append((item_id, child_id, 3, start_pos + idx))
                
                self.cursor.executemany(
                    "INSERT INTO item_item_assign (item_parent_id, item_child_id, type, position) VALUES (%s, %s, %s, %s)",
                    values
                )
                logger.info(f"Added {len(to_add)} alternative items to item {item_id}")
                changes_made = True
            
            # 5. Reihenfolge updaten wenn nötig
            if order_changed or to_add or to_delete:
                for idx, child_id in enumerate(new_items):
                    self.cursor.execute(
                        "UPDATE item_item_assign SET position = %s WHERE item_parent_id = %s AND item_child_id = %s AND type = 3",
                        (idx + 1, item_id, child_id)
                    )
                logger.info(f"Updated positions for item {item_id}")
                changes_made = True
            
            self.conn.commit()
            
            return {
                'success': True,
                'changes': {
                    'deleted': len(to_delete),
                    'added': len(to_add),
                    'reordered': order_changed
                },
                'message': 'Changes saved' if changes_made else 'No changes detected'
            }
            
        except Exception as e:
            self.conn.rollback()
            logger.error(f"Error saving alternative items: {str(e)}")
            return {
                'success': False,
                'error': str(e)
            }
    
    def save_accessory_items(self, item_id, new_items):
        """Type 1 = Zubehör - gleiche Logik"""
        return self._save_related_items(item_id, new_items, 1)
    
    def save_spare_parts(self, item_id, new_items):
        """Type 2 = Ersatzteile - gleiche Logik"""
        return self._save_related_items(item_id, new_items, 2)
    
    def _save_related_items(self, item_id, new_items, item_type):
        """Generische Methode für alle Verknüpfungstypen"""
        type_names = {1: 'accessory', 2: 'spare_part', 3: 'alternative'}
        
        try:
            # Gleiche Logik wie save_alternative_items
            self.cursor.execute(
                "SELECT item_child_id FROM item_item_assign WHERE item_parent_id = %s AND type = %s ORDER BY position",
                (item_id, item_type)
            )
            current_items = [row['item_child_id'] for row in self.cursor.fetchall()]
            
            new_items = [int(x) for x in new_items if x]
            
            to_delete = set(current_items) - set(new_items)
            to_add = set(new_items) - set(current_items)
            
            if to_delete:
                placeholders = ','.join(['%s'] * len(to_delete))
                self.cursor.execute(
                    f"DELETE FROM item_item_assign WHERE item_parent_id = %s AND item_child_id IN ({placeholders}) AND type = %s",
                    [item_id] + list(to_delete) + [item_type]
                )
            
            if to_add:
                # Position berechnen - bei erster Zuweisung start bei 1
                if not current_items:
                    start_pos = 1
                else:
                    start_pos = len(current_items) - len(to_delete) + 1
                    
                values = [(item_id, child_id, item_type, start_pos + idx) 
                         for idx, child_id in enumerate(to_add)]
                
                self.cursor.executemany(
                    "INSERT INTO item_item_assign (item_parent_id, item_child_id, type, position) VALUES (%s, %s, %s, %s)",
                    values
                )
            
            # Update positions
            for idx, child_id in enumerate(new_items):
                self.cursor.execute(
                    "UPDATE item_item_assign SET position = %s WHERE item_parent_id = %s AND item_child_id = %s AND type = %s",
                    (idx + 1, item_id, child_id, item_type)
                )
            
            self.conn.commit()
            
            logger.info(f"Saved {type_names[item_type]} items: {len(to_delete)} deleted, {len(to_add)} added")
            
            return {
                'success': True,
                'type': type_names[item_type],
                'changes': {
                    'deleted': len(to_delete),
                    'added': len(to_add)
                }
            }
            
        except Exception as e:
            self.conn.rollback()
            logger.error(f"Error saving {type_names[item_type]} items: {str(e)}")
            return {'success': False, 'error': str(e)}
    
    def close(self):
        """Cleanup"""
        if self.cursor:
            self.cursor.close()
        if self.conn:
            self.conn.close()

def main():
    """CLI Entry Point für PHP shell_exec()"""
    if len(sys.argv) < 2:
        print(json.dumps({'error': 'No data provided'}))
        sys.exit(1)
    
    try:
        # Parse input
        data = json.loads(sys.argv[1])
        item_id = data.get('item_id')
        action = data.get('action', 'save_all')
        
        service = ItemSaveService()
        
        if action == 'save_alternatives':
            items = data.get('items', [])
            result = service.save_alternative_items(item_id, items)
        elif action == 'save_accessories':
            items = data.get('items', [])
            result = service.save_accessory_items(item_id, items)
        elif action == 'save_spare_parts':
            items = data.get('items', [])
            result = service.save_spare_parts(item_id, items)
        elif action == 'save_all':
            # Alle 3 Typen speichern
            results = {}
            if 'alternatives' in data:
                results['alternatives'] = service.save_alternative_items(item_id, data['alternatives'])
            if 'accessories' in data:
                results['accessories'] = service.save_accessory_items(item_id, data['accessories'])
            if 'spare_parts' in data:
                results['spare_parts'] = service.save_spare_parts(item_id, data['spare_parts'])
            result = {'success': True, 'results': results}
        else:
            result = {'error': f'Unknown action: {action}'}
        
        service.close()
        
        # Return JSON
        print(json.dumps(result))
        
    except Exception as e:
        logger.error(f"Main error: {str(e)}")
        print(json.dumps({'error': str(e)}))
        sys.exit(1)

if __name__ == '__main__':
    main()