"""Network device plugin models."""

from shopdb.api import db, BaseModel


class NetworkDeviceType(BaseModel):
    """
    Network device type classification.

    Examples: Switch, Router, Access Point, Camera, IDF, Firewall, etc.
    """
    __tablename__ = 'networkdevicetypes'

    networkdevicetypeid = db.Column(db.Integer, primary_key=True)
    networkdevicetype = db.Column(db.String(100), unique=True, nullable=False)
    description = db.Column(db.Text)
    icon = db.Column(db.String(50), comment='Icon name for UI')
    color = db.Column(db.String(20), comment='CSS color for UI/map markers')
    # Asset-number prefix for devices of this type: AP-<name>, SW-<name>.
    # NULLABLE on purpose - a type with no prefix generates the bare name, so
    # nobody has to invent one for a type that does not want it.
    #
    # It cannot be derived from the type NAME: 'Access Point' and 'Access Panel'
    # both initialise to AP, and assetnumber is unique, so the second type would
    # collide with the first on every device.
    prefix = db.Column(
        db.String(12),
        comment='Asset-number prefix for this type (AP, SW, SVR). Blank = none')

    def __repr__(self):
        return f"<NetworkDeviceType {self.networkdevicetype}>"


class NetworkDevice(BaseModel):
    """
    Network device-specific extension data.

    Links to core Asset table via assetid.
    Stores network device-specific fields like hostname, firmware, ports, etc.
    """
    __tablename__ = 'networkdevices'

    networkdeviceid = db.Column(db.Integer, primary_key=True)

    # Link to core asset
    assetid = db.Column(
        db.Integer,
        db.ForeignKey('assets.assetid', ondelete='CASCADE'),
        unique=True,
        nullable=False,
        index=True
    )

    # Network device classification
    networkdevicetypeid = db.Column(
        db.Integer,
        db.ForeignKey('networkdevicetypes.networkdevicetypeid'),
        nullable=True
    )

    # Vendor
    modelnumberid = db.Column(
        db.Integer,
        db.ForeignKey('models.modelnumberid'),
        nullable=True,
        comment='Catalog model, which is where the device photo comes from'
    )

    vendorid = db.Column(
        db.Integer,
        db.ForeignKey('vendors.vendorid'),
        nullable=True
    )

    # Network identity
    hostname = db.Column(
        db.String(100),
        comment='Network hostname'
    )

    # Firmware/software version
    firmwareversion = db.Column(db.String(100), nullable=True)

    # Physical characteristics
    portcount = db.Column(
        db.Integer,
        nullable=True,
        comment='Number of ports (for switches)'
    )

    # Features
    ispoe = db.Column(
        db.Boolean,
        default=False,
        comment='Power over Ethernet capable'
    )
    ismanaged = db.Column(
        db.Boolean,
        default=False,
        comment='Managed device (SNMP, web interface, etc.)'
    )

    # For IDF/closet locations
    rackunit = db.Column(
        db.String(20),
        nullable=True,
        comment='Rack unit position (e.g., U1, U5)'
    )

    # Relationships
    asset = db.relationship(
        'Asset',
        backref=db.backref('network_device', uselist=False, lazy='joined')
    )
    networkdevicetype = db.relationship('NetworkDeviceType', backref='networkdevices')
    vendor = db.relationship('Vendor', backref='network_devices')
    model = db.relationship('Model', backref='network_devices')

    __table_args__ = (
        db.Index('idx_netdev_type', 'networkdevicetypeid'),
        db.Index('idx_netdev_hostname', 'hostname'),
        db.Index('idx_netdev_vendor', 'vendorid'),
    )

    def __repr__(self):
        return f"<NetworkDevice {self.hostname or self.assetid}>"

    def to_dict(self):
        """Convert to dictionary with related names."""
        result = super().to_dict()

        # Add related object names
        if self.networkdevicetype:
            result['networkdevicetypename'] = self.networkdevicetype.networkdevicetype
        if self.vendor:
            result['vendorname'] = self.vendor.vendor
        # Same shape as machines, PCs and printers: the detail page's hero image
        # binds to imageurl, and it comes from the catalog model, not the device.
        if self.model:
            result['modelname'] = self.model.modelnumber
            if self.model.imageurl:
                result['imageurl'] = self.model.imageurl
            # The catalog model already knows its maker, so an asset that has a
            # model but no vendor of its own is showing a blank the database can
            # fill. Flagged rather than merged silently: the edit form still has
            # an empty vendor box, and a page implying otherwise would be lying.
            if not self.vendor and self.model.vendor:
                result['vendorname'] = self.model.vendor.vendor
                result['vendorfrommodel'] = True
            # Exposed under its OWN name. modeltypes is the catalog-wide list
            # covering every kind of asset, so it is not interchangeable with
            # this asset's own type and must never be substituted for it.
            if self.model.modeltype:
                result['modeltypename'] = self.model.modeltype.modeltype

        return result
