import csv
import psycopg2
from proteus import config, Model


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

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

# PostgreSQL Configuration (for direct database access)
DB_HOST = '72.61.163.139'   
DB_PORT = 5433                      
DB_USER = 'postgres'            
DB_PASSWORD = 'dsproject'   

# Default values
DEFAULT_TYPE = 'storage'  # Default location type if not specified


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:
        config.set_xmlrpc(f'{HTTPS}{USERNAME}:{PASSWORD}@{SERVER_URL}/{DATABASE_NAME}/')
        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_db_connection():
    """Get PostgreSQL database connection"""
    try:
        conn = psycopg2.connect(
            host=DB_HOST,
            port=DB_PORT,
            database=DATABASE_NAME,
            user=DB_USER,
            password=DB_PASSWORD
        )
        return conn
    except Exception as e:
        print(f"✗ Database connection failed: {e}")
        return None

def update_location_coordinates(location_id, latitude, longitude):
    """Update location coordinates directly in PostgreSQL"""
    conn = get_db_connection()
    if not conn:
        print(f"  ⚠ Could not update coordinates - database connection failed")
        return False
    
    try:
        cursor = conn.cursor()
        
        # Update lat and lon columns
        update_query = """
            UPDATE stock_location 
            SET lat = %s, lon = %s 
            WHERE id = %s
        """
        
        cursor.execute(update_query, (latitude, longitude, location_id))
        rows_affected = cursor.rowcount
        conn.commit()
        
        cursor.close()
        conn.close()
        return rows_affected > 0
        
    except Exception as e:
        print(f"  ⚠ Error updating coordinates: {e}")
        import traceback
        traceback.print_exc()
        if conn:
            conn.rollback()
            conn.close()
        return False

def check_location_exists_by_name(name):
    """Check if location with given name already exists"""
    Location = Model.get('stock.location')
    locations = Location.find([('name', '=', name)])
    return locations[0] if locations else None

def validate_location_type(loc_type):
    """Validate location type"""
    valid_types = [
        'supplier', 'customer', 'lost_found', 'warehouse', 
        'storage', 'production', 'drop', 'rental', 'view'
    ]
    
    if not loc_type or loc_type.lower() not in valid_types:
        print(f"  ⚠ Warning: Invalid type '{loc_type}', using default '{DEFAULT_TYPE}'")
        return DEFAULT_TYPE
    
    return loc_type.lower()

def parse_coordinate(value, coord_name):
    """Parse and validate coordinate value"""
    if not value or value == '':
        return None
    
    # Handle 'NULL' or similar string values
    if isinstance(value, str) and value.strip().upper() in ['NULL', 'NONE', 'N/A', '']:
        return None
    
    try:
        coord = float(value)
        
        # Validate latitude range (-90 to 90)
        if coord_name == 'latitude':
            if coord < -90 or coord > 90:
                print(f"  ⚠ Warning: Latitude {coord} out of range (-90 to 90)")
                return None
        
        # Validate longitude range (-180 to 180)
        if coord_name == 'longitude':
            if coord < -180 or coord > 180:
                print(f"  ⚠ Warning: Longitude {coord} out of range (-180 to 180)")
                return None
        
        return coord
    except (ValueError, TypeError) as e:
        print(f"  ⚠ Warning: Invalid {coord_name} value '{value}' - {e}")
        return None

def create_location(row):
    """Create a new location using proteus"""
    Location = Model.get('stock.location')
    
    # Create location
    location = Location()
    location.name = row['name']
    location.type = row['type']
    
    # Save the location first
    location.save()
    
    # Get coordinates and save them
    latitude = row.get('latitude')
    longitude = row.get('longitude')
    
    # Update coordinates directly in database if provided
    if latitude is not None or longitude is not None:
        success = update_location_coordinates(location.id, latitude, longitude)
        if not success:
            print(f"  ⚠ Location created but coordinates not saved")
    
    return location, latitude, longitude

def import_locations(csv_file):
    """Import locations from CSV file"""
    
    imported_count = 0
    skipped_count = 0
    error_count = 0
    errors = []
    
    # Track names we've already processed in this run
    processed_names = set()
    
    print(f"{'='*70}")
    print(f"Importing locations 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 - get directly from CSV columns
                    name = row.get('name', '').strip()
                    loc_type = row.get('type', '').strip() or DEFAULT_TYPE
                    lat_raw = row.get('lat', '').strip()
                    lon_raw = row.get('lon', '').strip()
                    
                    # Skip empty rows
                    if not name:
                        continue
                    
                    print(f"Processing Row {row_num}: {name}")
                    print(f"    CSV Raw values - lat: '{lat_raw}', lon: '{lon_raw}'")
                    
                    # Check if we've already processed this name in this import run
                    if name in processed_names:
                        print(f"  ⚠ Duplicate name in CSV: '{name}'")
                        print(f"    Skipping duplicate entry...\n")
                        skipped_count += 1
                        continue
                    
                    # Check if location already exists in database
                    existing_location = check_location_exists_by_name(name)
                    
                    if existing_location:
                        print(f"  ⚠ Location '{name}' already exists (ID: {existing_location.id})")
                        print(f"    Type: {existing_location.type}")
                        print(f"    Skipping...\n")
                        skipped_count += 1
                        processed_names.add(name)
                        continue
                    
                    # Validate location type
                    loc_type = validate_location_type(loc_type)
                    
                    # Parse coordinates
                    latitude = parse_coordinate(lat_raw, 'latitude')
                    longitude = parse_coordinate(lon_raw, 'longitude')
                    
                    print(f"    Parsed values - lat: {latitude}, lon: {longitude}")
                    
                    # Create the location with parsed data
                    location_data = {
                        'name': name,
                        'type': loc_type,
                        'latitude': latitude,
                        'longitude': longitude
                    }
                    
                    location, saved_lat, saved_lon = create_location(location_data)
                    
                    # Mark this name as processed
                    processed_names.add(name)
                    
                    print(f"  ✓ Created location")
                    print(f"    Location ID: {location.id}")
                    print(f"    Name: {name}")
                    print(f"    Type: {loc_type}")
                    if saved_lat is not None:
                        print(f"    Latitude: {saved_lat}")
                    if saved_lon is not None:
                        print(f"    Longitude: {saved_lon}")
                    print()
                    
                    imported_count += 1
                    
                except Exception as e:
                    error_msg = f"Row {row_num} - {name if 'name' in locals() else 'Unknown'}: {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} locations")
        print(f"Skipped (already exist or duplicates): {skipped_count} locations")
        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 locations with coordinates from database"""
    Location = Model.get('stock.location')
    
    print(f"\n{'='*70}")
    print("VERIFICATION - Stock Locations")
    print(f"{'='*70}\n")
    
    # Get database connection to read coordinates
    conn = get_db_connection()
    
    if not conn:
        print("Cannot verify - database connection failed")
        return
    
    # Find all locations (or limit to recently created ones)
    locations = Location.find([], order=[('id', 'DESC')])
    
    if locations:
        print(f"Found {len(locations)} locations (showing last 20):\n")
        print(f"{'ID':<8} {'Name':<35} {'Type':<12} {'Lat':<12} {'Lon':<12}")
        print("-" * 85)
        
        for location in locations[:20]:  # Show last 20 created
            loc_id = location.id
            name = location.name[:34] if location.name else 'N/A'
            loc_type = location.type if location.type else 'N/A'
            
            # Get coordinates from database
            lat = 'N/A'
            lon = 'N/A'
            
            try:
                cursor = conn.cursor()
                cursor.execute(
                    "SELECT lat, lon FROM stock_location WHERE id = %s",
                    (loc_id,)
                )
                result = cursor.fetchone()
                if result:
                    lat = f"{result[0]:.6f}" if result[0] is not None else 'N/A'
                    lon = f"{result[1]:.6f}" if result[1] is not None else 'N/A'
                cursor.close()
            except Exception as e:
                print(f"Error reading coordinates for location {loc_id}: {e}")
            
            print(f"{loc_id:<8} {name:<35} {loc_type:<12} {lat:<12} {lon:<12}")
        
        conn.close()
    else:
        print("No locations found")
    
    print()

def main():
    print("="*70)
    print("TRYTON STOCK LOCATION IMPORT SCRIPT")
    print("Using Proteus with XML-RPC Connection")
    print("Using Direct PostgreSQL for lat/lon coordinates")
    print("="*70)
    print()
    
    # Connect to Tryton using XML-RPC
    if not connect_to_tryton():
        return 1
    
    # Test database connection
    print("Testing PostgreSQL connection...")
    conn = get_db_connection()
    if conn:
        print("✓ PostgreSQL connection successful")
        
        # Test if lat/lon columns exist
        try:
            cursor = conn.cursor()
            cursor.execute("""
                SELECT column_name, data_type 
                FROM information_schema.columns 
                WHERE table_name = 'stock_location' 
                AND column_name IN ('lat', 'lon')
            """)
            columns = cursor.fetchall()
            cursor.close()
            
            if columns:
                print("✓ Found lat/lon columns in stock_location table:")
                for col in columns:
                    print(f"  - {col[0]}: {col[1]}")
            else:
                print("✗ WARNING: lat/lon columns NOT found in stock_location table!")
                print("  Coordinates will not be saved!")
        except Exception as e:
            print(f"  Could not verify columns: {e}")
        
        conn.close()
        print()
    else:
        print("✗ PostgreSQL connection failed")
        print("Coordinates will not be saved!\n")
        return 1
    
    # Import locations
    import_locations(CSV_FILE_PATH)
    
    # Verify import
    verify_import()
    
    return 0

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