"""
For documentation on this script, run with -h flag
"""
from __future__ import division

import sys
import logging
import os
import time
import pandas as pd

from argparse import ArgumentParser
from argparse import RawTextHelpFormatter
from datetime import datetime as dt


def run_app():
    """Run the logic of application"""
    fc, logger = get_input_parameter()

    start_time = time.time()
    input_fc = fc

    logger.info('    Python ' + sys.version)

    # Set the Geoprocessing environment...
    arcpy.OverwriteOutput = 1

    logger.info('    - Setting Up Workspace')

    if not arcpy.Exists(input_fc):
        logger.error(' **** User-specified input feature class does not exist: ' + input_fc)
        sys.exit(100)

    check_unique_projpolyid(input_fc, logger)

    end_time = time.time()
    execution_time = sanitize_elapsed_time(end_time - start_time)

    logger.info('    Execution Time: ' + execution_time)
    logger.info('Next Script: StandardizeNoData')
    logger.info('Preconditions for next step: None')


def get_input_parameter():
    try:
        # Parse arguments
        parser = ArgumentParser(description='This script reports duplicate or null values '
                                            'found in the PROJPOLYID field of the input feature class.'
                                            'The script will simply report on screen that duplicates were detected, '
                                            'and list the first ten duplicate values found.',
                                formatter_class=RawTextHelpFormatter)
        parser.add_argument('fc', help='Feature class to be validated (long table feature class in an FGDB).')
        parser.add_argument('--log_level', default='INFO', choices=['DEBUG', 'INFO', 'WARNING', 'ERROR'],
                            help='Log level')
        parser.add_argument('--log_dir', help='Path to log Directory')
        args = parser.parse_args()

        log_name = 'main_logger'
        logger = logging.getLogger(log_name)

        log_fmt = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
        log_file_base_name = os.path.basename(sys.argv[0])
        log_file_extension = 'log'
        timestamp = dt.now().strftime('%Y-%m-%d_%H-%M-%S')
        log_file = "{}_{}.{}".format(timestamp, log_file_base_name, log_file_extension)

        logger.setLevel(args.log_level)

        sh = logging.StreamHandler()
        sh.setLevel(args.log_level)
        sh.setFormatter(log_fmt)
        logger.addHandler(sh)

        if args.log_dir:
            try:
                os.makedirs(args.log_dir)
            except OSError:
                pass

            fh = logging.FileHandler(os.path.join(args.log_dir, log_file))
            fh.setLevel(args.log_level)
            fh.setFormatter(log_fmt)
            logger.addHandler(fh)

        return args.fc, logger

    except Exception as e:
        print('Unexpected exception. Program terminating.')
        exit(1)


def check_unique_projpolyid(input_fc, logger):
    logger.info('    - Checking uniqueness of PROJPOLYID')

    # check if PROJPOLYID field exists
    if "PROJPOLYID" not in [f.name for f in arcpy.ListFields(input_fc)]:
        logger.error(' **** Input feature class does not contain a PROJPOLYID field.')
        sys.exit(100)

    else:
        # Use a set to keep track of unique values
        unique_values = set()
        # Create a list to hold the duplicate values
        duplicate_values = []

        # Create a search cursor to iterate through the feature class
        with arcpy.da.SearchCursor(input_fc, ['PROJPOLYID']) as cursor:
            for row in cursor:
                # if the value is null or an empty string, error out
                if row[0] is None or row[0] == '':
                    logger.error('    **** Null or empty string PROJPOLYID value(s) found. Fix nulls and re-run.')
                    sys.exit(100)
                # Check if the value is already in the unique_values set
                if row[0] in unique_values:
                    # If it is, add it to the duplicate_values list
                    duplicate_values.append(row[0])
                    # Check if we've found 10 duplicates yet
                    if len(duplicate_values) == 10:
                        # If we have, break out of the loop
                        break
                else:
                    # If it's not in the unique_values set, add it
                    unique_values.add(row[0])


    # if there are duplicates, error and exit
    if duplicate_values:
        logger.error('    **** Duplicate PROJPOLYID value(s) found. Listing up to the first ten '
                        'duplicate values found: ' + str(duplicate_values).replace('[', '').replace(']', '').
                        replace(' ', '').replace('None', '<Null>') + '\nFix duplicate PROJPOLYIDs and re-run.')
        sys.exit(100)
    
    else:
        logger.info('        - No duplicate or null PROJPOLYID values found.')             


def stra(value):
    """
    Converts any value to a string. Replaces Python's stra() which incurs an error if the value
    happens to have a unicode character in it. Unicode characters will be replaced with ?

    :param any value: input value
    :return: value as string
    :rtype: str
    """
    if sys.version_info[0] < 3:
        return unicode(value).encode('ascii', 'replace')
    else:
        return str(value)


def sanitize_elapsed_time(seconds):
    """
    Routine to convert a raw number of seconds into a human-friendly statement of duration

    :param seconds: number of seconds
    :return: formatted duration
    :rtype: str
    """

    if seconds < 120:
        str_elapsed_time = stra(int(seconds)) + ' seconds.'
    elif seconds < 3600:
        str_elapsed_time = stra(int(seconds)) + ' seconds (' + stra(round(seconds / 60, 1)) + ' minutes).'
    else:
        str_elapsed_time = stra(int(seconds)) + ' seconds (' + stra(round(seconds / 3600, 2)) + ' hours).'

    return str_elapsed_time


if __name__ == '__main__':
    try:
        # Import arcpy
        import arcpy
    except:
        logging.error('No ArcGIS licenses available to run this tool.  Program terminating.')
        sys.exit(1)
    run_app()
else:
    try:
        # Import arcpy
        import arcpy
    except:
        logging.error('No ArcGIS licenses available to run this tool.  Program terminating.')
        sys.exit(1)
