"""
Copyright © 2019-2024 Ralph Seichter

This file is part of automx2.

automx2 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

automx2 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with automx2. If not, see <https://www.gnu.org/licenses/>.
"""

from flask_sqlalchemy import SQLAlchemy

from automx2 import PLACEHOLDER_ADDRESS

db = SQLAlchemy()

davserver_domain_map = db.Table(
    'davserver_domain',
    db.Column('davserver_id', db.Integer, db.ForeignKey('davserver.id'), primary_key=True),
    db.Column('domain_id', db.Integer, db.ForeignKey('domain.id'), primary_key=True)
)
server_domain_map = db.Table(
    'server_domain',
    db.Column('server_id', db.Integer, db.ForeignKey('server.id'), primary_key=True),
    db.Column('domain_id', db.Integer, db.ForeignKey('domain.id'), primary_key=True)
)


class Provider(db.Model):
    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    name = db.Column(db.String(128), nullable=False)
    short_name = db.Column(db.String(32), nullable=False)
    domains = db.relationship('Domain', lazy='select', backref=db.backref('provider', lazy='joined'))

    def __repr__(self) -> str:
        return f'<Provider id={self.id} name={self.short_name}>'


class Server(db.Model):
    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    prio = db.Column(db.Integer, nullable=False, server_default='10')
    name = db.Column(db.String(128), nullable=False)
    port = db.Column(db.Integer, nullable=False)
    type = db.Column(db.String(32), nullable=False)
    socket_type = db.Column(db.String(32), nullable=False, default='STARTTLS')
    user_name = db.Column(db.String(64), nullable=False, default=PLACEHOLDER_ADDRESS)
    authentication = db.Column(db.String(32), nullable=False, default='plain')
    domains = db.relationship('Domain', secondary=server_domain_map, lazy='subquery',
                              backref=db.backref('servers', lazy='select'))

    def __repr__(self) -> str:
        return f'<Server id={self.id} prio={self.prio} type={self.type} name={self.name}>'


class Davserver(db.Model):
    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    url = db.Column(db.String(128), nullable=False)
    port = db.Column(db.Integer, nullable=False, default=0)
    type = db.Column(db.String(32), nullable=False)
    use_ssl = db.Column(db.Boolean, nullable=False)
    domain_required = db.Column(db.Boolean, nullable=False)
    user_name = db.Column(db.String(64), nullable=True)
    domains = db.relationship('Domain', secondary=davserver_domain_map, lazy='subquery',
                              backref=db.backref('davservers', lazy='select'))

    def __repr__(self) -> str:
        return f'<Davserver id={self.id} type={self.type} url={self.url}>'


class Ldapserver(db.Model):
    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    name = db.Column(db.String(128), nullable=False)
    port = db.Column(db.Integer, nullable=False)
    use_ssl = db.Column(db.Boolean, nullable=False)
    search_base = db.Column(db.String(128), nullable=False)
    search_filter = db.Column(db.String(128), nullable=False)
    attr_uid = db.Column(db.String(32), nullable=False)
    attr_cn = db.Column(db.String(32), nullable=True)
    bind_password = db.Column(db.String(128), nullable=True)
    bind_user = db.Column(db.String(128), nullable=True)
    domains = db.relationship('Domain', lazy='select', backref=db.backref('ldapserver', lazy='joined'))

    def __repr__(self) -> str:
        return f'<Ldapserver id={self.id} name={self.name}>'


class Domain(db.Model):
    id = db.Column(db.Integer, nullable=False, primary_key=True, autoincrement=True)
    name = db.Column(db.String(128), nullable=False, unique=True)
    provider_id = db.Column(db.Integer, db.ForeignKey('provider.id'), nullable=False)
    ldapserver_id = db.Column(db.Integer, db.ForeignKey('ldapserver.id'), nullable=True)

    def __repr__(self) -> str:
        return f'<Domain id={self.id} name={self.name}>'
