from typing import Optional, List
import sqlalchemy
from sqlmodel import SQLModel, Field, Relationship
from datetime import date, datetime


# #############################################################################
# Links
class ListingFacilityLink(SQLModel, table=True):
    listing_id: int = Field(
        foreign_key="listings.id", primary_key=True
    )
    facility_id: int = Field(
        foreign_key="facilities.id", primary_key=True
    )


# #############################################################################


class SongBase(SQLModel):
    id: Optional[int]
    name: str
    artist: str
    year: Optional[int] = None


class Song(SongBase, table=True):
    id: int = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})


class SongRead(SongBase):
    id: int
    created_at: datetime
    updated_at: datetime


class SongUpdate(SQLModel):
    name: Optional[str] = None
    artist: Optional[str] = None
    year: Optional[int] = None


class SongCreate(SongBase):
    pass


class Increment(SQLModel, table=True):
    id: int = Field(primary_key=True)


# #############################################################################
class ListingBase(SQLModel):
    id: int = Field(primary_key=True)
    is_active: bool
    title: Optional[str] = None
    description: Optional[str] = None
    url: str
    source: str
    source_id: str
    source_code: Optional[str] = None
    address: str
    short_postal_code: Optional[str] = None
    property_type: Optional[str] = None
    postal_code: Optional[str] = None
    ber_code: Optional[str] = None
    views: Optional[int] = None

    bedrooms: Optional[int] = None
    bathrooms: Optional[int] = None

    price: Optional[int] = None
    rating_auto: Optional[int] = None
    rating_user: Optional[int] = None
    telegram_sent_at: Optional[datetime] = None
    images_count: Optional[int] = 0
    latitude: Optional[float] = None
    longitude: Optional[float] = None
    notes: Optional[str] = None
    publish_date: Optional[datetime] = None
    last_updated: Optional[datetime] = None


class Listing(ListingBase, table=True):
    __tablename__ = 'listings'
    id: int = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})
    images: List["Image"] = Relationship(back_populates="listing",
        # sa_relationship_kwargs={'lazy': 'joined'}
    )
    facilities: List["Facility"] = Relationship(link_model=ListingFacilityLink)
    places_nearby: List["PlaceNearby"] = Relationship(
        back_populates="listing",)
    routes: List["Route"] = Relationship(back_populates="listing",)


class ListingRead(ListingBase):
    id: str
    created_at: datetime
    updated_at: datetime


class ListingCreate(ListingBase):
    pass
class ListingUpdate(ListingBase):
    id: Optional[str]
    is_active: Optional[bool]
    url: Optional[str]
    source: Optional[str]
    source_id: Optional[str]
    address: Optional[str]

# #############################################################################


class FacilityBase(SQLModel):
    id: Optional[int]
    name: str
    category: Optional[str] = None
    notes: Optional[str] = None


class Facility(FacilityBase, table=True):
    __tablename__ = 'facilities'
    id: int = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})


class FacilityRead(FacilityBase):
    id: int
    created_at: datetime
    updated_at: datetime


class FacilityCreate(FacilityBase):
    pass


# #############################################################################


class ImageBase(SQLModel):
    id: Optional[int]
    url: str
    url_600: Optional[str]
    size_x: Optional[float]
    size_y: Optional[float]
    listing_id: Optional[int] = Field(default=None, foreign_key="listings.id")


class Image(ImageBase, table=True):
    __tablename__ = 'images'
    id: int = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})
    listing: Optional[Listing] = Relationship(back_populates="images",
                                              #   sa_relationship_kwargs={'lazy': 'selectin'}
                                              )


class ImageRead(ImageBase):
    id: int
    created_at: datetime
    updated_at: datetime


class ImageCreate(ImageBase):
    pass

# #############################################################################


class PlaceNearbyBase(SQLModel):
    id: Optional[int]
    latitude: Optional[float] = None
    longitude: Optional[float] = None
    query: Optional[str] = None
    name: str
    address: str
    distance: int
    website: Optional[str] = None
    website_domain: Optional[str] = None
    chain_name: Optional[str] = None
    listing_id: Optional[int] = Field(default=None, foreign_key="listings.id")


class PlaceNearby(PlaceNearbyBase, table=True):
    __tablename__ = 'places_nearby'
    id: Optional[int] = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})
    listing: Optional[Listing] = Relationship(back_populates="places_nearby",)


class PlaceNearbyRead(PlaceNearbyBase):
    id: int
    created_at: datetime
    updated_at: datetime


class PlaceNearbyCreate(PlaceNearbyBase):
    pass

# #############################################################################


class InterestPointBase(SQLModel):
    id: Optional[int]
    name: str
    is_active: bool
    latitude: Optional[float] = None
    longitude: Optional[float] = None


class InterestPoint(InterestPointBase, table=True):
    __tablename__ = 'interest_points'
    id: Optional[int] = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(default=datetime.now(),
                                 sa_column_kwargs={'onupdate': datetime.now()})


class InterestPointRead(InterestPointBase):
    id: int
    created_at: datetime
    updated_at: datetime


class InterestPointCreate(InterestPointBase):
    pass

# #############################################################################


class RouteBase(SQLModel):
    id: Optional[int]
    waking_distance: Optional[int] = 0
    total_distance: Optional[int] = 0
    total_time: Optional[int] = 0
    public_transport_count: Optional[int] = 0
    
    listing_id: Optional[int] = Field(default=None, foreign_key="listings.id")
    interest_point_id: Optional[int] = Field(
        default=None, foreign_key="interest_points.id")


class Route(RouteBase, table=True):
    __tablename__ = 'routes'
    id: int = Field(primary_key=True)
    created_at: datetime = Field(default=datetime.now())
    updated_at: datetime = Field(
        default=datetime.now(),
        sa_column_kwargs={'onupdate': datetime.now()})

    listing: Optional[Listing] = Relationship(back_populates="routes",)
    interest_point: Optional[InterestPoint] = Relationship()
    

class RouteRead(RouteBase):
    id: int
    created_at: datetime
    updated_at: datetime


class RouteCreate(RouteBase):
    id: Optional[int] = None


# #############################################################################


# #############################################################################


class ImageReadWithListings(ImageRead):
    listing: Optional[Listing] = None


class ListingReadWithRelations(ListingRead):
    images: List["ImageRead"] = []
    facilities: List["Facility"] = []
    places_nearby: List["PlaceNearby"] = []
    routes: List["Route"] = []

class ListingCreateWithRelations(ListingCreate):
    images: List["ImageCreate"] = []
    facilities: List["Facility"] = []
datetime.datetime.now sqlmodel.Relationship sqlmodel.Field
[((300, 350), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""listings.id"""', 'primary_key': '(True)'}), "(foreign_key='listings.id', primary_key=True)\n", (305, 350), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((388, 440), 'sqlmodel.Field', 'Field', ([], {'foreign_key': '"""facilities.id"""', 'primary_key': '(True)'}), "(foreign_key='facilities.id', primary_key=True)\n", (393, 440), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((698, 721), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (703, 721), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((1225, 1248), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (1230, 1248), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((1374, 1397), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (1379, 1397), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((2327, 2350), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (2332, 2350), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((2573, 2611), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""listing"""'}), "(back_populates='listing')\n", (2585, 2611), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((2705, 2749), 'sqlmodel.Relationship', 'Relationship', ([], {'link_model': 'ListingFacilityLink'}), '(link_model=ListingFacilityLink)\n', (2717, 2749), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((2791, 2829), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""listing"""'}), "(back_populates='listing')\n", (2803, 2829), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((2868, 2906), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""listing"""'}), "(back_populates='listing')\n", (2880, 2906), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((3547, 3570), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (3552, 3570), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((4171, 4217), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'foreign_key': '"""listings.id"""'}), "(default=None, foreign_key='listings.id')\n", (4176, 4217), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((4299, 4322), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (4304, 4322), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((4550, 4587), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""images"""'}), "(back_populates='images')\n", (4562, 4587), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((5301, 5347), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'foreign_key': '"""listings.id"""'}), "(default=None, foreign_key='listings.id')\n", (5306, 5347), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((5458, 5481), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (5463, 5481), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((5709, 5753), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""places_nearby"""'}), "(back_populates='places_nearby')\n", (5721, 5753), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((6277, 6300), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (6282, 6300), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((6986, 7032), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'foreign_key': '"""listings.id"""'}), "(default=None, foreign_key='listings.id')\n", (6991, 7032), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((7072, 7125), 'sqlmodel.Field', 'Field', ([], {'default': 'None', 'foreign_key': '"""interest_points.id"""'}), "(default=None, foreign_key='interest_points.id')\n", (7077, 7125), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((7216, 7239), 'sqlmodel.Field', 'Field', ([], {'primary_key': '(True)'}), '(primary_key=True)\n', (7221, 7239), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((7452, 7489), 'sqlmodel.Relationship', 'Relationship', ([], {'back_populates': '"""routes"""'}), "(back_populates='routes')\n", (7464, 7489), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((7537, 7551), 'sqlmodel.Relationship', 'Relationship', ([], {}), '()\n', (7549, 7551), False, 'from sqlmodel import SQLModel, Field, Relationship\n'), ((763, 777), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (775, 777), False, 'from datetime import date, datetime\n'), ((820, 834), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (832, 834), False, 'from datetime import date, datetime\n'), ((2392, 2406), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (2404, 2406), False, 'from datetime import date, datetime\n'), ((2449, 2463), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (2461, 2463), False, 'from datetime import date, datetime\n'), ((3612, 3626), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (3624, 3626), False, 'from datetime import date, datetime\n'), ((3669, 3683), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (3681, 3683), False, 'from datetime import date, datetime\n'), ((4364, 4378), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (4376, 4378), False, 'from datetime import date, datetime\n'), ((4421, 4435), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (4433, 4435), False, 'from datetime import date, datetime\n'), ((5523, 5537), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (5535, 5537), False, 'from datetime import date, datetime\n'), ((5580, 5594), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (5592, 5594), False, 'from datetime import date, datetime\n'), ((6342, 6356), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (6354, 6356), False, 'from datetime import date, datetime\n'), ((6399, 6413), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (6411, 6413), False, 'from datetime import date, datetime\n'), ((7281, 7295), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (7293, 7295), False, 'from datetime import date, datetime\n'), ((7347, 7361), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (7359, 7361), False, 'from datetime import date, datetime\n'), ((899, 913), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (911, 913), False, 'from datetime import date, datetime\n'), ((2528, 2542), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (2540, 2542), False, 'from datetime import date, datetime\n'), ((3748, 3762), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (3760, 3762), False, 'from datetime import date, datetime\n'), ((4500, 4514), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (4512, 4514), False, 'from datetime import date, datetime\n'), ((5659, 5673), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (5671, 5673), False, 'from datetime import date, datetime\n'), ((6478, 6492), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (6490, 6492), False, 'from datetime import date, datetime\n'), ((7401, 7415), 'datetime.datetime.now', 'datetime.now', ([], {}), '()\n', (7413, 7415), False, 'from datetime import date, datetime\n')]