# -*- coding: utf-8 -*-
"""
stego_lsb.cli
~~~~~~~~~~~~~

This module provides the command line interface for:
    - hiding and recovering data in .wav files
    - hiding and recovering data in bitmap (.bmp and .png)
      files
    - detecting images which have modified using the
      LSB methods.

TODO: should this be refactored more? I am trusting that @sh4nks implemented this well.

:copyright: (c) 2015 by Ryan Gibson, see AUTHORS.md for more details.
:license: MIT License, see LICENSE.md for more details.
"""
import logging

import click

from stego_lsb import LSBSteg, StegDetect, WavSteg, bit_manipulation

# enable logging output
logging.basicConfig(format="%(message)s", level=logging.INFO)
log = logging.getLogger("stego_lsb")
log.setLevel(logging.DEBUG)


@click.group()
@click.version_option()
def main() -> None:
    """Console script for stegolsb."""


@main.command(context_settings=dict(max_content_width=120))
@click.option("--hide", "-h", is_flag=True, help="To hide data in an image file")
@click.option("--recover", "-r", is_flag=True, help="To recover data from an image file")
@click.option("--analyze", "-a", is_flag=True, default=False, show_default=True,
              help="Print how much data can be hidden within an image")
@click.option("--input", "-i", "input_fp", help="Path to an bitmap (.bmp or .png) image")
@click.option("--secret", "-s", "secret_fp", help="Path to a file to hide in the image")
@click.option("--output", "-o", "output_fp", help="Path to an output file")
@click.option("--lsb-count", "-n", default=2, show_default=True, help="How many LSBs to use", type=int)
@click.option("--compression", "-c", help="1 (best speed) to 9 (smallest file size)", default=1, show_default=True,
              type=click.IntRange(1, 9))
@click.pass_context
def steglsb(ctx: click.Context, hide: bool, recover: bool, analyze: bool, input_fp: str, secret_fp: str, output_fp: str,
            lsb_count: int, compression: int) -> None:
    """Hides or recovers data in and from an image"""
    try:
        if analyze:
            LSBSteg.analysis(input_fp, secret_fp, lsb_count)

        if hide:
            LSBSteg.hide_data(input_fp, secret_fp, output_fp, lsb_count, compression)
        elif recover:
            LSBSteg.recover_data(input_fp, output_fp, lsb_count)

        if not hide and not recover and not analyze:
            click.echo(ctx.get_help())
    except ValueError as e:
        log.debug(e)
        click.echo(ctx.get_help())


@main.command()
@click.option("--input", "-i", "image_path", help="Path to an image")
@click.option("--lsb-count", "-n", default=2, show_default=2, type=int, help="How many LSBs to display")
@click.pass_context
def stegdetect(ctx: click.Context, image_path: str, lsb_count: int) -> None:
    """Shows the n least significant bits of image"""
    if image_path:
        StegDetect.show_lsb(image_path, lsb_count)
    else:
        click.echo(ctx.get_help())


@main.command()
@click.option("--hide", "-h", is_flag=True, help="To hide data in a sound file")
@click.option("--recover", "-r", is_flag=True, help="To recover data from a sound file")
@click.option("--input", "-i", "input_fp", help="Path to a .wav file")
@click.option("--secret", "-s", "secret_fp", help="Path to a file to hide in the sound file")
@click.option("--output", "-o", "output_fp", help="Path to an output file")
@click.option("--lsb-count", "-n", default=2, show_default=True, help="How many LSBs to use", type=int)
@click.option("--bytes", "-b", "num_bytes", help="How many bytes to recover from the sound file", type=int)
@click.pass_context
def wavsteg(ctx: click.Context, hide: bool, recover: bool, input_fp: str, secret_fp: str, output_fp: str,
            lsb_count: int, num_bytes: int) -> None:
    """Hides or recovers data in and from a sound file"""
    try:
        if hide:
            WavSteg.hide_data(input_fp, secret_fp, output_fp, lsb_count)
        elif recover:
            WavSteg.recover_data(input_fp, output_fp, lsb_count, num_bytes)
        else:
            click.echo(ctx.get_help())
    except ValueError as e:
        log.debug(e)
        click.echo(ctx.get_help())


@main.command()
def test() -> None:
    """Runs a performance test and verifies decoding consistency"""
    bit_manipulation.test()
