import csv
from proteus import config, Model
from decimal import Decimal

# XML-RPC Configuration
HTTPS = 'https://'
SERVER_URL = 'itsa.open-squared.tech'
DATABASE_NAME = 'tradon'
USERNAME = 'admin'
PASSWORD = 'dsproject'

# CSV Configuration
CSV_FILE_PATH = r'C:\Users\SylvainDUVERNAY\Open Squared\Production - Documents\TRADON Implementation\ITSA\Reference Data\Loaders\Services.csv'  # UPDATE THIS PATH!

# Product configuration
PRODUCT_TYPE = 'service'  # Service type products
DEFAULT_CATEGORY = 'SERVICES'  # Default category name if not found
DEFAULT_UOM = 'Mt'  # Default UOM if not found

def connect_to_tryton():
    """Establish connection to Tryton via XML-RPC"""
    print(f"Connecting to Tryton server: {SERVER_URL}")
    print(f"Database: {DATABASE_NAME}")
    print(f"Username: {USERNAME}")


    try:
        # Connect using XML-RPC with credentials in URL
        #connection_url = f'{SERVER_URL}/{DATABASE_NAME}/'
        #print(f'{USERNAME}:{PASSWORD}@{connection_url}')

        config.set_xmlrpc(f'{HTTPS}{USERNAME}:{PASSWORD}@{SERVER_URL}/{DATABASE_NAME}/')
        
        #config.set_xmlrpc('https://admin:dsproject@itsa.open-squared.tech/tradon/')

        print("✓ Connected successfully!\n")
        return True
    except Exception as e:
        print(f"✗ Connection failed: {e}")
        print("\nTroubleshooting:")
        print("  - Verify the server URL is correct and accessible")
        print("  - Check that the Tryton server is running")
        print("  - Verify username and password are correct")
        print("  - Make sure you can access the server in a browser")
        return False

def get_or_create_category(category_name):
    """Find or create a product category"""
    Category = Model.get('product.category')
    
    # Try to find existing category
    categories = Category.find([('name', '=', category_name)])
    
    if categories:
        print(f"  Found existing category: {category_name}")
        return categories[0]
    else:
        # Create new category
        new_category = Category()
        new_category.name = category_name
        new_category.save()
        print(f"  ✓ Created new category: {category_name}")
        return new_category

def get_uom(uom_name):
    """Find Unit of Measure by name"""
    Uom = Model.get('product.uom')
    
    # Try exact match first
    uoms = Uom.find([('name', '=', uom_name)])
    
    if uoms:
        return uoms[0]
    
    # Try case-insensitive search by getting all and comparing
    all_uoms = Uom.find([])
    for uom in all_uoms:
        if uom.name.lower() == uom_name.lower():
            return uom
    
    # If not found, try to get default 'Unit'
    print(f"  ⚠ Warning: UOM '{uom_name}' not found, using '{DEFAULT_UOM}'")
    default_uoms = Uom.find([('name', '=', DEFAULT_UOM)])
    if default_uoms:
        return default_uoms[0]
    
    # If even Unit is not found, get the first available
    all_uoms = Uom.find([])
    if all_uoms:
        print(f"  ⚠ Using first available UOM: {all_uoms[0].name}")
        return all_uoms[0]
    
    raise ValueError("No UOM found in database!")

def check_product_exists(code):
    """Check if product with given code already exists"""
    Product = Model.get('product.product')
    products = Product.find([('code', '=', code)])
    return products[0] if products else None

def create_service_product(row, categories, uom):
    """Create a new service product using proteus"""
    Template = Model.get('product.template')
    
    # Create template
    template = Template()
    template.name = row['name']
    template.code = row['code']
    template.type = PRODUCT_TYPE
    template.list_price = Decimal(row['sale_price']) if row['sale_price'] else Decimal('0.00')
    template.cost_price_method = 'fixed'  # Services use fixed cost price
    template.default_uom = uom
    
    # Link to categories (Many2Many relationship)
    # Use append() instead of direct assignment
    if isinstance(categories, list):
        template.categories.extend(categories)  # Use extend for lists
    else:
        template.categories.append(categories)  # Use append for single category
    
    template.salable = False    # Services are not salable products by default
    template.purchasable = True  # Services are purchasable  
    
    if row.get('description'):
        template.description = row['description']
    
    # Save the template first
    template.save()
    
    # Now update the product that was auto-created
    # When a template is created, Tryton automatically creates a default product
    if template.products:
        product = template.products[0]
        #product.code = row['code']
        product.suffix_code = row['code']  # Use suffix_code to set product code
        
        # Set cost price on the product
        product.cost_price = Decimal(row['cost_price']) if row['cost_price'] else Decimal('0.00')
        
        product.save()
        return product
    else:
        raise ValueError("No product was created automatically with template")

def import_services(csv_file):
    """Import services from CSV file"""
    
    imported_count = 0
    skipped_count = 0
    error_count = 0
    errors = []
    
    print(f"{'='*70}")
    print(f"Importing service products from: {csv_file}")
    print(f"{'='*70}\n")
    
    try:
        # Open with utf-8-sig to handle BOM
        with open(csv_file, 'r', encoding='utf-8-sig') as file:
            reader = csv.DictReader(file)
            
            # Debug: Show detected columns
            print(f"Detected columns: {reader.fieldnames}\n")
            
            for row_num, row in enumerate(reader, start=2):
                try:
                    # Clean up values
                    code = row.get('code', '').strip()
                    name = row.get('name', '').strip()
                    category_name = row.get('category', DEFAULT_CATEGORY).strip() or DEFAULT_CATEGORY
                    uom_name = row.get('uom', DEFAULT_UOM).strip() or DEFAULT_UOM
                    sale_price = row.get('sale_price', '0.00').strip() or '0.00'
                    cost_price = row.get('cost_price', '0.00').strip() or '0.00'
                    description = row.get('description', '').strip()
                    
                    # Skip empty rows
                    if not code and not name:
                        continue
                    
                    # Validate required fields
                    if not code or not name:
                        errors.append(f"Row {row_num}: Missing code or name")
                        error_count += 1
                        print(f"✗ Row {row_num}: Missing required fields")
                        continue
                    
                    print(f"Processing Row {row_num}: {code} - {name}")
                    
                    # Check if product already exists
                    existing_product = check_product_exists(code)
                    
                    if existing_product:
                        print(f"  ⚠ Product code '{code}' already exists: {existing_product.template.name}")
                        print(f"    Skipping...\n")
                        skipped_count += 1
                        continue
                    
                    # Get or create category
                    category = get_or_create_category(category_name)
                    
                    # Get UOM
                    uom = get_uom(uom_name)
                    print(f"  Using UOM: {uom.name}")
                    
                    # Create the product
                    row_data = {
                        'code': code,
                        'name': name,
                        'sale_price': sale_price,
                        'cost_price': cost_price,
                        'description': description
                    }
                    
                    product = create_service_product(row_data, category, uom)
                    
                    print(f"  ✓ Created service product")
                    print(f"    Product ID: {product.id}, Template ID: {product.template.id}")
                    print(f"    Code: {code}")
                    print(f"    Category: {category.name}")
                    print(f"    Sale Price: {sale_price}")
                    print(f"    Cost Price: {cost_price}")
                    if description:
                        print(f"    Description: {description[:50]}...")
                    print()
                    
                    imported_count += 1
                    
                except Exception as e:
                    error_msg = f"Row {row_num} - {code} ({name}): {str(e)}"
                    errors.append(error_msg)
                    error_count += 1
                    print(f"✗ Error on row {row_num}: {e}\n")
                    import traceback
                    traceback.print_exc()
        
        # Summary
        print(f"{'='*70}")
        print("IMPORT SUMMARY")
        print(f"{'='*70}")
        print(f"Successfully imported: {imported_count} service products")
        print(f"Skipped (already exist): {skipped_count} products")
        print(f"Errors: {error_count}")
        
        if errors:
            print(f"\nError details:")
            for error in errors:
                print(f"  - {error}")
        
        print(f"\n{'='*70}")
        
    except FileNotFoundError:
        print(f"✗ Error: CSV file not found at {csv_file}")
        print(f"Please update CSV_FILE_PATH in the script with the correct path.")
    except Exception as e:
        print(f"✗ Fatal error: {e}")
        import traceback
        traceback.print_exc()

def verify_import():
    """Verify imported service products"""
    Product = Model.get('product.product')
    
    print(f"\n{'='*70}")
    print("VERIFICATION - Service Products")
    print(f"{'='*70}\n")
    
    # Find all service type products
    products = Product.find([('template.type', '=', 'service')])
    
    if products:
        print(f"Found {len(products)} service products:\n")
        print(f"{'Code':<12} {'Name':<30} {'Categories':<25} {'Sale Price':<12}")
        print("-" * 85)
        
        for product in products:
            code = product.code or 'N/A'
            name = product.template.name[:29] if product.template.name else 'N/A'
            
            # Get categories (Many2Many relationship)
            if product.template.categories:
                categories = ', '.join([cat.name for cat in product.template.categories])
                categories = categories[:24]
            else:
                categories = 'N/A'
            
            sale_price = f"{product.template.list_price:.2f}" if product.template.list_price else '0.00'
            
            print(f"{code:<12} {name:<30} {categories:<25} {sale_price:<12}")
    else:
        print("No service products found")
    
    print()

def list_available_uoms():
    """List all available UOMs in the database"""
    print(f"\n{'='*70}")
    print("AVAILABLE UNITS OF MEASURE")
    print(f"{'='*70}\n")
    
    Uom = Model.get('product.uom')
    uoms = Uom.find([])
    
    if uoms:
        print(f"Found {len(uoms)} UOMs:\n")
        for uom in uoms:
            symbol = f"({uom.symbol})" if hasattr(uom, 'symbol') and uom.symbol else ""
            print(f"  - {uom.name} {symbol}")
    else:
        print("No UOMs found")
    
    print()

def list_available_categories():
    """List all available product categories"""
    print(f"\n{'='*70}")
    print("AVAILABLE PRODUCT CATEGORIES")
    print(f"{'='*70}\n")
    
    Category = Model.get('product.category')
    categories = Category.find([])
    
    if categories:
        print(f"Found {len(categories)} categories:\n")
        for cat in categories:
            print(f"  - {cat.name}")
    else:
        print("No categories found")
    
    print()

def main():
    print("="*70)
    print("TRYTON SERVICE PRODUCT IMPORT SCRIPT")
    print("Using Proteus with XML-RPC Connection")
    print("="*70)
    print()
    
    # Connect to Tryton using XML-RPC
    if not connect_to_tryton():
        return 1
    
    # Optional: List available UOMs and categories
    # Uncomment these if you want to see what's available in your database
    # list_available_uoms()
    # list_available_categories()
    
    # Import service products
    import_services(CSV_FILE_PATH)
    
    # Verify import
    verify_import()
    
    return 0

if __name__ == '__main__':
    exit(main())