# Helper methods for printing `host` information to the terminal.
import click

from shodan.helpers import get_ip


def host_print_pretty(host, history=False):
    """Show the host information in a user-friendly way and try to include
    as much relevant information as possible."""
    # General info
    click.echo(click.style(get_ip(host), fg='green'))
    if len(host['hostnames']) > 0:
        click.echo(u'{:25s}{}'.format('Hostnames:', ';'.join(host['hostnames'])))

    if 'city' in host and host['city']:
        click.echo(u'{:25s}{}'.format('City:', host['city']))

    if 'country_name' in host and host['country_name']:
        click.echo(u'{:25s}{}'.format('Country:', host['country_name']))

    if 'os' in host and host['os']:
        click.echo(u'{:25s}{}'.format('Operating System:', host['os']))

    if 'org' in host and host['org']:
        click.echo(u'{:25s}{}'.format('Organization:', host['org']))

    if 'last_update' in host and host['last_update']:
        click.echo('{:25s}{}'.format('Updated:', host['last_update']))

    click.echo('{:25s}{}'.format('Number of open ports:', len(host['ports'])))

    # Output the vulnerabilities the host has
    if 'vulns' in host and len(host['vulns']) > 0:
        vulns = []
        for vuln in host['vulns']:
            if vuln.startswith('!'):
                continue
            if vuln.upper() == 'CVE-2014-0160':
                vulns.append(click.style('Heartbleed', fg='red'))
            else:
                vulns.append(click.style(vuln, fg='red'))

        if len(vulns) > 0:
            click.echo('{:25s}'.format('Vulnerabilities:'), nl=False)

            for vuln in vulns:
                click.echo(vuln + '\t', nl=False)

            click.echo('')

    click.echo('')

    # If the user doesn't have access to SSL/ Telnet results then we need
    # to pad the host['data'] property with empty banners so they still see
    # the port listed as open. (#63)
    if len(host['ports']) != len(host['data']):
        # Find the ports the user can't see the data for
        ports = host['ports']
        for banner in host['data']:
            if banner['port'] in ports:
                ports.remove(banner['port'])

        # Add the placeholder banners
        for port in ports:
            banner = {
                'port': port,
                'transport': 'tcp',  # All the filtered services use TCP
                'timestamp': host['data'][-1]['timestamp'],  # Use the timestamp of the oldest banner
                'placeholder': True,  # Don't store this banner when the file is saved
            }
            host['data'].append(banner)

    click.echo('Ports:')
    for banner in sorted(host['data'], key=lambda k: k['port']):
        product = ''
        version = ''
        if 'product' in banner and banner['product']:
            product = banner['product']
        if 'version' in banner and banner['version']:
            version = '({})'.format(banner['version'])

        click.echo(click.style('{:>7d}'.format(banner['port']), fg='cyan'), nl=False)
        if 'transport' in banner:
            click.echo('/', nl=False)
            click.echo(click.style('{} '.format(banner['transport']), fg='yellow'), nl=False)
        click.echo('{} {}'.format(product, version), nl=False)

        if history:
            # Format the timestamp to only show the year-month-day
            date = banner['timestamp'][:10]
            click.echo(click.style('\t\t({})'.format(date), fg='white', dim=True), nl=False)
        click.echo('')

        # Show optional HTTP information
        if 'http' in banner:
            if 'title' in banner['http'] and banner['http']['title']:
                click.echo('\t|-- HTTP title: {}'.format(banner['http']['title']))

        # Show optional ssl info
        if 'ssl' in banner:
            if 'cert' in banner['ssl'] and banner['ssl']['cert']:
                if 'issuer' in banner['ssl']['cert'] and banner['ssl']['cert']['issuer']:
                    issuer = ', '.join(['{}={}'.format(key, value) for key, value in banner['ssl']['cert']['issuer'].items()])
                    click.echo('\t|-- Cert Issuer: {}'.format(issuer))
                if 'subject' in banner['ssl']['cert'] and banner['ssl']['cert']['subject']:
                    subject = ', '.join(['{}={}'.format(key, value) for key, value in banner['ssl']['cert']['subject'].items()])
                    click.echo('\t|-- Cert Subject: {}'.format(subject))
            if 'versions' in banner['ssl'] and banner['ssl']['versions']:
                click.echo('\t|-- SSL Versions: {}'.format(', '.join([item for item in sorted(banner['ssl']['versions']) if not version.startswith('-')])))
            if 'dhparams' in banner['ssl'] and banner['ssl']['dhparams']:
                click.echo('\t|-- Diffie-Hellman Parameters:')
                click.echo('\t\t{:15s}{}\n\t\t{:15s}{}'.format('Bits:', banner['ssl']['dhparams']['bits'], 'Generator:', banner['ssl']['dhparams']['generator']))
                if 'fingerprint' in banner['ssl']['dhparams']:
                    click.echo('\t\t{:15s}{}'.format('Fingerprint:', banner['ssl']['dhparams']['fingerprint']))


def host_print_tsv(host, history=False):
    """Show the host information in a succinct, grep-friendly manner."""
    for banner in sorted(host['data'], key=lambda k: k['port']):
        click.echo(click.style('{:>7d}'.format(banner['port']), fg='cyan'), nl=False)
        click.echo('\t', nl=False)
        click.echo(click.style('{} '.format(banner['transport']), fg='yellow'), nl=False)

        if history:
            # Format the timestamp to only show the year-month-day
            date = banner['timestamp'][:10]
            click.echo(click.style('\t({})'.format(date), fg='white', dim=True), nl=False)
        click.echo('')


HOST_PRINT = {
    'pretty': host_print_pretty,
    'tsv': host_print_tsv,
}
