import requests
import os
from time import sleep, time
from .Exceptions import MaxRetriesException
from ._util import saveAsFile
from ._util import _printErrorMessage
from ._PollLog import _PollLog

class _DataProductFile:
    """
    Donwloads a single data product file
    Is able to poll and wait if required
    """

    def __init__(self, dpRunId: int, index: str, baseUrl: str, token: str):
        self._retries     = 0
        self._status      = 202
        self._downloaded  = False
        self._baseUrl     = '{:s}api/dataProductDelivery'.format(baseUrl)
        self._filePath    = ''
        self._fileSize    = 0
        self._runningTime = 0
        self._downloadingTime = 0

        self._filters = {
            'method' : 'download',
            'token'  : token,
            'dpRunId': dpRunId,
            'index'  : index
        }
        # prepopulate download URL in case download() never happens
        self._downloadUrl = '{:s}?method=download&token={:s}&dpRunId={:d}&index={:s}'.format(baseUrl, token, dpRunId, index)

    
    def download(self, timeout: int, pollPeriod: float, outPath: str, maxRetries: int, overwrite: bool):
        """
        Download a file for the data product at runId
        Can poll, wait and retry if the file is not ready to download
        Return the file information
        """
        #print('\ndonwload()')
        log = _PollLog(True)
        try:
            self._status = 202
            while self._status == 202:
                # Run timed request
                start = time()
                response = requests.get(self._baseUrl, self._filters, timeout=timeout)
                duration = time() - start
                
                self._downloadUrl = response.url
                self._status = response.status_code
                self._retries += 1
                
                #print('request got {:d}'.format(response.status_code))
                if maxRetries > 0 and self._retries > maxRetries:
                    raise MaxRetriesException('   Maximum number of retries ({:d}) exceeded'.format(maxRetries))
                
                # Status 200: file downloaded, 202: processing, 204: no data, 400: error, 404: index out of bounds, 410: gone (file deleted from FTP) 
                if self._status == 200:
                    # File downloaded, get filename from header and save
                    self._downloaded = True
                    self._downloadingTime = round(duration, 3)
                    filename = self.extractNameFromHeader(response)

                    saveAsFile(response, outPath, filename, overwrite)
                    self._filePath = outPath + '/' + filename
                    self._fileSize = len(response.content)
                
                elif self._status == 202:
                    # Still processing, wait and retry
                    log.logMessage(response.json())
                    #print('')
                    #print(response.json())
                    sleep(pollPeriod)
                
                elif self._status == 204:
                    # No data found
                    print('   No data found.')
                
                elif self._status == 400:
                    # API Error
                    _printErrorMessage(response)
                    raise Exception('The request failed with HTTP status {:d}.'.format(self._status), response.json())
                
                elif self._status == 404:
                    # Index too high, no more files to download
                    log.printNewLine()
                    pass

                else:
                    # Gone
                    print('   FTP Error: File not found. If this product order is recent, retry downloading this product using the method downloadProduct with the runId: ' + runId)
                    _printErrorMessage(response)
        
        except Exception:
            raise

        #print('retries: {:d}'.format(self._retries))
        return self._status


    def extractNameFromHeader(self, response):
        """
        In a download request response 200, extracts and returns the file name from the response
        """
        txt = response.headers['Content-Disposition']
        filename = txt.split('filename=')[1]
        return filename

    
    def setComplete(self):
        self._status = 200


    def getInfo(self, download: bool=False):
        errorCodes = {
            '200': 'complete',
            '202': 'running',
            '204': 'no content',
            '400': 'error',
            '401': 'unauthorized',
            '404': 'not found',
            '410': 'gone',
            '500': 'server error'
        }

        txtStatus = errorCodes[str(self._status)]
        
        return {
            'url'             : self._downloadUrl,
            'status'          : txtStatus,
            'size'            : self._fileSize,
            'file'            : self._filePath,
            'index'           : self._filters['index'],
            'downloaded'      : self._downloaded,
            'requestCount'    : self._retries,
            'fileDownloadTime': float(self._downloadingTime)
        }