#!/usr/bin/env python3
"""
Vehicle Database Manager
A script to initialize and manage the vehicle database with brands, years, models, and engines
"""

import sqlite3
import os
from datetime import datetime
from typing import List, Tuple


class VehicleDatabaseManager:
    def __init__(self, db_path: str = "vehicle_database.db"):
        self.db_path = db_path
        self.connection = None
    
    def connect(self):
        """Connect to the SQLite database"""
        self.connection = sqlite3.connect(self.db_path)
        self.connection.row_factory = sqlite3.Row  # Enable column access by name
        print(f"Connected to database: {self.db_path}")
    
    def disconnect(self):
        """Close the database connection"""
        if self.connection:
            self.connection.close()
            print("Disconnected from database")
    
    def create_tables(self, schema_file: str = "sql/schema.sql"):
        """Create tables from schema file"""
        if not os.path.exists(schema_file):
            raise FileNotFoundError(f"Schema file not found: {schema_file}")
        
        with open(schema_file, 'r') as f:
            schema = f.read()
        
        if self.connection:
            cursor = self.connection.cursor()
            cursor.executescript(schema)
            self.connection.commit()
            print("Tables created successfully")
    
    def insert_brand(self, name: str, country: str = None, founded_year: int = None) -> int:
        """Insert a new brand and return its ID"""
        cursor = self.connection.cursor()
        cursor.execute(
            "INSERT OR IGNORE INTO brands (name, country, founded_year) VALUES (?, ?, ?)",
            (name, country, founded_year)
        )
        self.connection.commit()
        # Return the ID of the inserted or existing brand
        cursor.execute("SELECT id FROM brands WHERE name = ?", (name,))
        return cursor.fetchone()[0]
    
    def insert_engine(self, name: str, displacement_cc: float = None, cylinders: int = None, 
                      fuel_type: str = None, power_hp: int = None, torque_nm: int = None, 
                      engine_code: str = None) -> int:
        """Insert a new engine and return its ID"""
        cursor = self.connection.cursor()
        cursor.execute(
            """INSERT OR IGNORE INTO engines 
               (name, displacement_cc, cylinders, fuel_type, power_hp, torque_nm, engine_code) 
               VALUES (?, ?, ?, ?, ?, ?, ?)""",
            (name, displacement_cc, cylinders, fuel_type, power_hp, torque_nm, engine_code)
        )
        self.connection.commit()
        # Return the ID of the inserted or existing engine
        cursor.execute("SELECT id FROM engines WHERE name = ?", (name,))
        return cursor.fetchone()[0]
    
    def insert_model(self, brand_id: int, name: str, body_type: str = None, 
                     generation: str = None, production_start_year: int = None, 
                     production_end_year: int = None) -> int:
        """Insert a new model and return its ID"""
        cursor = self.connection.cursor()
        cursor.execute(
            """INSERT OR IGNORE INTO models 
               (brand_id, name, body_type, generation, production_start_year, production_end_year) 
               VALUES (?, ?, ?, ?, ?, ?)""",
            (brand_id, name, body_type, generation, production_start_year, production_end_year)
        )
        self.connection.commit()
        # Return the ID of the inserted or existing model
        cursor.execute("SELECT id FROM models WHERE brand_id = ? AND name = ?", (brand_id, name))
        return cursor.fetchone()[0]
    
    def insert_year(self, year: int) -> int:
        """Insert a new year and return its ID"""
        cursor = self.connection.cursor()
        cursor.execute("INSERT OR IGNORE INTO years (year) VALUES (?)", (year,))
        self.connection.commit()
        # Return the ID of the inserted or existing year
        cursor.execute("SELECT id FROM years WHERE year = ?", (year,))
        return cursor.fetchone()[0]
    
    def insert_model_year_engine(self, model_id: int, year_id: int, engine_id: int, 
                                 trim_level: str = None, drivetrain: str = None, 
                                 transmission: str = None):
        """Insert a model-year-engine combination"""
        cursor = self.connection.cursor()
        cursor.execute(
            """INSERT OR REPLACE INTO model_year_engine 
               (model_id, year_id, engine_id, trim_level, drivetrain, transmission) 
               VALUES (?, ?, ?, ?, ?, ?)""",
            (model_id, year_id, engine_id, trim_level, drivetrain, transmission)
        )
        self.connection.commit()
    
    def get_brands(self) -> List[Tuple]:
        """Retrieve all brands"""
        cursor = self.connection.cursor()
        cursor.execute("SELECT * FROM brands ORDER BY name")
        return cursor.fetchall()
    
    def get_models_by_brand(self, brand_id: int) -> List[Tuple]:
        """Retrieve all models for a specific brand"""
        cursor = self.connection.cursor()
        cursor.execute("""
            SELECT m.*, b.name as brand_name 
            FROM models m 
            JOIN brands b ON m.brand_id = b.id 
            WHERE m.brand_id = ?
            ORDER BY m.name
        """, (brand_id,))
        return cursor.fetchall()
    
    def get_vehicle_info(self, brand_name: str = None, model_name: str = None, 
                         year: int = None, engine_name: str = None) -> List[Tuple]:
        """Get comprehensive vehicle information based on filters"""
        query = """
            SELECT 
                b.name AS brand,
                m.name AS model,
                y.year,
                e.name AS engine,
                e.displacement_cc,
                e.cylinders,
                e.fuel_type,
                e.power_hp,
                e.torque_nm,
                e.engine_code,
                mye.trim_level,
                mye.drivetrain,
                mye.transmission
            FROM model_year_engine mye
            JOIN models m ON mye.model_id = m.id
            JOIN brands b ON m.brand_id = b.id
            JOIN years y ON mye.year_id = y.id
            JOIN engines e ON mye.engine_id = e.id
            WHERE 1=1
        """
        
        params = []
        if brand_name:
            query += " AND b.name LIKE ?"
            params.append(f"%{brand_name}%")
        if model_name:
            query += " AND m.name LIKE ?"
            params.append(f"%{model_name}%")
        if year:
            query += " AND y.year = ?"
            params.append(year)
        if engine_name:
            query += " AND e.name LIKE ?"
            params.append(f"%{engine_name}%")
        
        query += " ORDER BY b.name, m.name, y.year"
        
        cursor = self.connection.cursor()
        cursor.execute(query, params)
        return cursor.fetchall()


def populate_sample_data(db_manager: VehicleDatabaseManager):
    """Populate the database with sample data"""
    print("Populating sample data...")
    
    # Insert sample brands
    toyota_id = db_manager.insert_brand("Toyota", "Japan", 1937)
    honda_id = db_manager.insert_brand("Honda", "Japan", 1948)
    ford_id = db_manager.insert_brand("Ford", "USA", 1903)
    bmw_id = db_manager.insert_brand("BMW", "Germany", 1916)
    
    # Insert sample engines
    engine_2jz = db_manager.insert_engine(
        "2JZ-GTE", 
        displacement_cc=3000, 
        cylinders=6, 
        fuel_type="gasoline", 
        power_hp=320, 
        torque_nm=450, 
        engine_code="2JZ-GTE"
    )
    
    engine_k20 = db_manager.insert_engine(
        "K20C1", 
        displacement_cc=2000, 
        cylinders=4, 
        fuel_type="gasoline", 
        power_hp=280, 
        torque_nm=260, 
        engine_code="K20C1"
    )
    
    engine_ecoboost = db_manager.insert_engine(
        "EcoBoost V6", 
        displacement_cc=3500, 
        cylinders=6, 
        fuel_type="gasoline", 
        power_hp=375, 
        torque_nm=470, 
        engine_code="EcoBoost V6"
    )
    
    engine_n52 = db_manager.insert_engine(
        "N52B30", 
        displacement_cc=3000, 
        cylinders=6, 
        fuel_type="gasoline", 
        power_hp=255, 
        torque_nm=310, 
        engine_code="N52B30"
    )
    
    # Insert sample models
    camry_id = db_manager.insert_model(
        toyota_id, 
        "Camry", 
        body_type="sedan", 
        generation="XV70", 
        production_start_year=2017, 
        production_end_year=None
    )
    
    civic_id = db_manager.insert_model(
        honda_id, 
        "Civic", 
        body_type="sedan", 
        generation="XI", 
        production_start_year=2016, 
        production_end_year=None
    )
    
    mustang_id = db_manager.insert_model(
        ford_id, 
        "Mustang", 
        body_type="coupe", 
        generation="S550", 
        production_start_year=2015, 
        production_end_year=None
    )
    
    x3_id = db_manager.insert_model(
        bmw_id, 
        "X3", 
        body_type="suv", 
        generation="G01", 
        production_start_year=2017, 
        production_end_year=None
    )
    
    # Insert years
    year_2020 = db_manager.insert_year(2020)
    year_2021 = db_manager.insert_year(2021)
    year_2022 = db_manager.insert_year(2022)
    
    # Link models, years, and engines
    db_manager.insert_model_year_engine(civic_id, year_2020, engine_k20, "Sport", "FWD", "automatic")
    db_manager.insert_model_year_engine(mustang_id, year_2020, engine_ecoboost, "GT", "RWD", "automatic")
    db_manager.insert_model_year_engine(x3_id, year_2021, engine_n52, "xDrive30i", "AWD", "automatic")
    db_manager.insert_model_year_engine(camry_id, year_2022, engine_k20, "SE", "FWD", "automatic")
    
    print("Sample data populated successfully!")


def main():
    # Initialize the database manager
    db_manager = VehicleDatabaseManager()
    
    try:
        # Connect to database
        db_manager.connect()
        
        # Create tables
        db_manager.create_tables()
        
        # Populate with sample data
        populate_sample_data(db_manager)
        
        # Demonstrate queries
        print("\n--- All Brands ---")
        brands = db_manager.get_brands()
        for brand in brands:
            print(f"ID: {brand['id']}, Name: {brand['name']}, Country: {brand['country']}")
        
        print(f"\n--- Models for Toyota (ID: {brands[0]['id']}) ---")
        toyota_models = db_manager.get_models_by_brand(brands[0]['id'])
        for model in toyota_models:
            print(f"Model: {model['name']}, Body Type: {model['body_type']}")
        
        print("\n--- All Vehicle Information ---")
        all_vehicles = db_manager.get_vehicle_info()
        for vehicle in all_vehicles:
            print(f"{vehicle['brand']} {vehicle['model']} {vehicle['year']} - "
                  f"{vehicle['engine']} ({vehicle['power_hp']} HP)")
        
        print("\n--- Search for Honda Civic ---")
        honda_civic = db_manager.get_vehicle_info(brand_name="Honda", model_name="Civic")
        for vehicle in honda_civic:
            print(f"{vehicle['brand']} {vehicle['model']} {vehicle['year']} - "
                  f"{vehicle['engine']} ({vehicle['power_hp']} HP)")
    
    except Exception as e:
        print(f"An error occurred: {e}")
    
    finally:
        # Close the connection
        db_manager.disconnect()


if __name__ == "__main__":
    main()