from .connections import DatabaseConnection
from .managers import Manager
from .fields import Field, IntegerField

class ModelMeta(type):
    def __new__(cls, name, bases, attrs):
        if name != 'Model':
            fields = {k: v for k, v in attrs.items() if isinstance(v, Field)}
            attrs['_fields'] = fields
            attrs['_table_name'] = name.lower()
            attrs['objects'] = Manager()
            for field_name, field in fields.items():
                if field.primary_key:
                    attrs['_pk_field'] = field_name
                    break
            else:
                attrs['_pk_field'] = 'id'
                attrs['id'] = IntegerField(primary_key=True)
                attrs['_fields']['id'] = attrs['id']
        return super().__new__(cls, name, bases, attrs)
    


class Model(metaclass=ModelMeta):
    def __init__(self, **kwargs):
        self._data = {}

        for field_name in self._fields:
            self._data[field_name] = None   # default value

        for field_name, value in kwargs.items():
            if field_name in self._fields:
                self._data[field_name] = value
            else:
                raise ValueError(
                    f"Unknown field '{field_name}' on {self.__class__.__name__}"
                )
            

    def __getattribute__(self, name):
        _fields = object.__getattribute__(self, "_fields")
        
        if name in _fields:
            _data = object.__getattribute__(self, "_data")
            return _data.get(name)

        return object.__getattribute__(self, name)
    

    def __setattr__(self, name, value):
        if name in ("_data", "_fields", "_pk_field", "_table_name"):
            super().__setattr__(name, value)
        # elif "_fields" in self.__dict__ and name in self._fields:
        elif hasattr(self, "_fields") and name in self._fields:
            self._data[name] = value
        else:
            super().__setattr__(name, value)

    @classmethod
    def create_table(cls):
        conn = DatabaseConnection.get_connection()
        cursor = conn.cursor()

        fields_def = []
        for name, field in cls._fields.items():
            col_type = field.db_type
            if name == "id" and isinstance(field, IntegerField) and field.primary_key:
                col_type = "SERIAL PRIMARY KEY"
            elif field.primary_key:
                col_type += " PRIMARY KEY"
            fields_def.append(f'"{name}" {col_type}')   # quote names → case preserving

        query = f"""
            CREATE TABLE IF NOT EXISTS "{cls._table_name}" (
                {', '.join(fields_def)}
            );
        """
        cursor.execute(query)
        conn.commit()
   
    def save(self):
        conn = DatabaseConnection.get_connection()
        cursor = conn.cursor()

        pk_name = self._pk_field
        pk_value = self._data.get(pk_name)

        print(pk_name, pk_value, "---------------")

        # Helper to get DB-safe value
        def get_real_value(field_name):
            value = self._data.get(field_name)

            # If value explicitly set → use it
            if value is not None:
                return value

            # Otherwise use default from field definition
            field_obj = self._fields[field_name]
            if field_obj.default is not None:
                return field_obj.default

            return None

        # ───────────────── UPDATE ─────────────────
        if pk_value is not None:
            set_clauses = []
            values = []

            for fname in self._fields:
                if fname == pk_name:
                    continue

                set_clauses.append(f'"{fname}" = %s')
                values.append(get_real_value(fname))

            values.append(pk_value)

            query = f"""
                UPDATE "{self._table_name}"
                SET {', '.join(set_clauses)}
                WHERE "{pk_name}" = %s
            """

        # ───────────────── INSERT ─────────────────
        else:
            columns = []
            placeholders = []
            values = []

            for fname, field in self._fields.items():

                # Skip auto primary key if value is None
                if fname == pk_name and self._data.get(pk_name) is None:
                    continue

                columns.append(f'"{fname}"')
                placeholders.append('%s')
                values.append(get_real_value(fname))

            query = f"""
                INSERT INTO "{self._table_name}" ({', '.join(columns)})
                VALUES ({', '.join(placeholders)})
                RETURNING "{pk_name}"
            """

        # ───────────────── DEBUG ─────────────────
        print("Executing query:")
        print(query)
        print("With values:", values)
        print("Value types:", [type(v).__name__ if v is not None else 'NoneType' for v in values])
        # ─────────────────────────────────────────

        cursor.execute(query, values)
        # If INSERT → set primary key
        if pk_value is None:
            row = cursor.fetchone()
            if row:
                self._data[pk_name] = row[pk_name]   # safer than setattr

        conn.commit()


    def delete(self):
        conn = DatabaseConnection.get_connection()
        pk_value = getattr(self, self._pk_field)
        query = f'DELETE FROM "{self._table_name}" WHERE "{self._pk_field}" = %s'
        conn.execute(query, (pk_value,))
        conn.commit()