"""
Copyright © 2019 Ralph Seichter

Graciously sponsored by sys4 AG <https://sys4.de/>

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
from automx2.util import unique

BIGCORP_NAME = 'Big Corporation, Inc.'
BIGCORP_SHORT = 'BigCorp'
EGGS_DOMAIN = 'ham-n-eggs.tld'
EGGS_NAME = 'Ham & Eggs'
EGGS_SHORT = 'H+E'
EXAMPLE_COM = 'example.com'
EXAMPLE_NET = 'example.net'
EXAMPLE_ORG = 'example.org'
ORPHAN_DOMAIN = 'orphan.tld'
OTHER_NAME = 'Some Other Provider'
OTHER_SHORT = 'SOP'
SERVERLESS_DOMAIN = 'serverless.tld'

sample_server_names = {
    'imap1': f'imap1.{unique()}.com',
    'imap2': f'imap2.{unique()}.com',
    'smtp1': f'primary-smtp.{unique()}.com',
    'smtp2': f'secondary-smtp.{unique()}.com',
}

db = SQLAlchemy()

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, nullable=False)
    short_name = db.Column(db.String, 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)
    port = db.Column(db.Integer, nullable=False)
    type = db.Column(db.String, nullable=False)
    name = db.Column(db.String, nullable=False)
    socket_type = db.Column(db.String, nullable=False, default='STARTTLS')
    user_name = db.Column(db.String, nullable=False, default=PLACEHOLDER_ADDRESS)
    authentication = db.Column(db.String, 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} type={self.type} name={self.name}>'


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

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


# noinspection DuplicatedCode
def populate_db():
    """Populate the database some fixed samples."""
    i = 1000
    bigcorp = Provider(id=i, name=BIGCORP_NAME, short_name=BIGCORP_SHORT)
    i += 1
    eggs = Provider(id=i, name=EGGS_NAME, short_name=EGGS_SHORT)
    i += 1
    other = Provider(id=i, name=OTHER_NAME, short_name=OTHER_SHORT)
    db.session.add_all([bigcorp, eggs, other])

    i = 2000
    ex_com = Domain(id=i, name=EXAMPLE_COM, provider=bigcorp)
    i += 1
    ex_net = Domain(id=i, name=EXAMPLE_NET, provider=bigcorp)
    i += 1
    ex_org = Domain(id=i, name=EXAMPLE_ORG, provider=bigcorp)
    i += 1
    eggs = Domain(id=i, name=EGGS_DOMAIN, provider=eggs)
    i += 1
    orphan = Domain(id=i, name=ORPHAN_DOMAIN, provider_id=(-1 * i))
    i += 1
    serverless = Domain(id=i, name=SERVERLESS_DOMAIN, provider=other)
    db.session.add_all([ex_com, ex_net, ex_org, eggs, orphan, serverless])

    i = 3000
    s1 = Server(id=i, type='smtp', port=587, name=sample_server_names['smtp1'], domains=[ex_com, ex_net])
    i += 1
    s2 = Server(id=i, type='smtp', port=587, name=sample_server_names['smtp2'], domains=[ex_org])
    i += 1
    s3 = Server(id=i, type='imap', port=143, name=sample_server_names['imap1'], domains=[ex_com])
    i += 1
    s4 = Server(id=i, type='imap', port=143, name=sample_server_names['imap2'], domains=[ex_net, ex_org])
    i += 1
    s5 = Server(id=i, type='INVALID', port=123, name=f'{unique()}.{EGGS_DOMAIN}', domains=[eggs])
    db.session.add_all([s1, s2, s3, s4, s5])
