#! /usr/bin/env python3
"""Show some lines from files"""

import os
import re
import sys

from pysyte import __version__
from pysyte import text_streams
from pysyte.cli.main import run


def parse_args(parser):
    """Parse out command line arguments"""
    p = parser
    p.positionals('files', help='files to edit')
    p.int('-a', '--at', default=None, help='Show line at the line number')
    p.boolean('-p', '--paste', help='Paste text from clipboard')
    p.boolean('-i', '--stdin', help='Wait for text from stdin')
    p.string('-f', '--first', default="1",
               help='number/regexp of first line to show')
    p.string('-l', '--last', default="0",
               help='number/regexp of last line to show')
    p.boolean('-n', '--numbers', help='Show line numbers')
    p.int('-w', '--width', help='Max width of shown line')
    p.boolean('-v', '--version', help='Show version')


def post_parse(args):
    if args.version:
        print(f'{sys.argv[0]} version: {__version__}')
        sys.exit(0)
    return args


def parse_lines(args, lines_read):

    def as_int(string, start):
        try:
            return int(string)
        except (ValueError, TypeError):
            matcher = re.compile(string)
            for i, line in enumerate(lines_read, 1):
                if i <= start:
                    continue
                if matcher.search(line):
                    return i
        return 0

    def _line(i):
        line = i if i >= 0 else length_read + 1 + i
        if line >= length_read:
            return length_read
        return 0 if line < 1 else line

    def _boundaries():
        if not args.at:
            first = _line(as_int(args.first, 0) - 1)
            last = _line(as_int(args.last, first) or -1)
            return first, last
        first = _line(args.at)
        return first, first + 1

    length_read = len(lines_read)
    first, last = _boundaries()
    lines = [] if first > length_read else lines_read[first:last]
    return lines, first


def line_format(lines):
    """A string format for line numbers

    Should give a '%d' format with width bug enough to accomodate the last line
    """
    last_line_number = len(lines)
    digits = len(str(last_line_number))
    return '%%%dd: ' % digits


def show_stream(stream, args):
    text = stream.read()
    lines_in = text.splitlines()
    lines, first = parse_lines(args, lines_in)
    line_format_ = line_format(lines)
    for i, line in enumerate(lines, first):
        if args.numbers:
            prefix = line_format_ % (i + 1)
            out = ' '.join((prefix, line.rstrip()))
        else:
            out = line.rstrip()
        if args.width:
            out = out[:args.width]
        print(out)


def main(args):
    """Run the script"""
    streams = text_streams.args(args, 'files')
    for stream in streams:
        show_stream(stream, args)
    return os.EX_OK


run(main, parse_args, post_parse)
