from datetime import datetime
from pathlib import Path
from typing import Union, Tuple, Optional, List
import pandas as pd

from tfv_get_tools.utilities._tfv_bc import write_tuflowfv_fvc
from tfv_get_tools.providers._downloader import BatchDownloadResult

def DownloadWave(
    start_date: Union[str, datetime, pd.Timestamp],
    end_date: Union[str, datetime, pd.Timestamp],
    xlims: Tuple[float, float],
    ylims: Tuple[float, float],
    out_path: Union[str, Path] = Path("./raw"),
    source: str = "CAWCR",
    model: str = "default",
    prefix: Optional[str] = None,
    verbose: bool = False,
    variables: Optional[List[str]] = None,
    skip_check: bool = False,
    **kwargs,
) -> BatchDownloadResult:
    """Download Wave Data
    
    Users should call this function, not the individual downloader classes directly.
    
    This module will download wave data from several possible sources to facilitate 
    TUFLOW FV and SWAN modelling.

    The following sources have been implemented:
        - `CAWCR` - CSIRO Ocean wave hindcast forced using NCEP's CFSR Atmospheric Model
            - `glob_24m` - Global domain at 24' resolution
            - `aus_10m` - Australia ribbon model domain at 10' resolution
            - `aus_4m` - Australia ribbon model domain at 4' resolution
            - `pac_10m` - Pacific island domain at 10' resolution
            - `pac_4m` - Pacific island domain at 4' resolution
        - `Copernicus` - Various models from the Copernicus Marine Service
            - `GLO` - Global wave model
        - `ERA5` - Global 0.5deg Wave model (WAM) from the European Centre for 
            Medium-Range Weather Forecasts (ECMWF)

    Args:
        start_date: Start date. The string format is `%Y-%m-%d` (e.g., '2011-01-01')
        end_date: End date. The string format is `%Y-%m-%d` (e.g., '2011-02-01')
        xlims: Minimum and maximum longitude, as floats. e.g., (115, 120)
        ylims: Minimum and maximum latitude, as floats. e.g., (-40, -35)
        out_path: Output directory for data files
        source: Data source to download. One of {'CAWCR', 'Copernicus', 'ERA5'}
        model: Choice of model, depending on "source"
        prefix: Extra file name prefix
        verbose: Print extra program information
        variables: List of variables to download
        skip_check: Skip user confirmation
        **kwargs: Additional arguments
        
    Returns:
        BatchDownloadResult: Results of the download operation
    """
    
    if source.lower() == "cawcr":
        from tfv_get_tools.providers.wave.cawcr import DownloadCAWCR
        
        downloader = DownloadCAWCR(
            start_date=start_date,
            end_date=end_date,
            xlims=xlims,
            ylims=ylims,
            out_path=out_path,
            model=model,
            prefix=prefix,
            verbose=verbose,
            variables=variables,
            skip_check=skip_check,
            **kwargs
        )
        return downloader.execute_download()
    
    elif source.lower() == "copernicus":
        from tfv_get_tools.providers.wave.copernicus_wave import DownloadCopernicusWave
        
        downloader = DownloadCopernicusWave(
            start_date=start_date,
            end_date=end_date,
            xlims=xlims,
            ylims=ylims,
            out_path=out_path,
            model=model,
            prefix=prefix,
            verbose=verbose,
            variables=variables,
            skip_check=skip_check,
            **kwargs
        )
        return downloader.execute_download()

    elif source.lower() == "era5":
        from tfv_get_tools.providers.wave.era5 import DownloadERA5Wave
        
        downloader = DownloadERA5Wave(
            start_date=start_date,
            end_date=end_date,
            xlims=xlims,
            ylims=ylims,
            out_path=out_path,
            model=model,
            prefix=prefix,
            verbose=verbose,
            variables=variables,
            skip_check=skip_check,
            **kwargs
        )
        return downloader.execute_download()
        
    else:
        raise ValueError(f'Unrecognised source {source}. Must be one of: CAWCR, Copernicus, ERA5')



def MergeWave(
    in_path: Path = Path("./raw"),
    out_path: Path = Path("."),
    fname: str = None,
    source: str = 'CAWCR',
    model: str = 'default',
    time_start: str = None,
    time_end: str = None,
    reproject: int = None,
    local_tz: Tuple[float, str] = None,
    wrapto360=False,
):
    """
    Merge raw downloaded wave datafiles into a single netcdf file. 
    
    **Use the same `source` and `model` that was supplied to the Downloader function**

    Args:
        in_path (Path, optional): Directory of the raw ocean data-files. Defaults to Path(".").
        out_path (Path, optional): Output directory for the merged ocean netcdf and (opt) the fvc. Defaults to Path(".").
        fname (str, optional): Merged ocean netcdf filename. Defaults to None.
        source (str, optional): Source to be merged, defaults to "CAWCR". 
        model (str, optional): Model for source to be merged. Defaults to 'default' (which is 'glob_24m' for CAWCR).
        time_start (str, optional): Start time limit of the merged dataset (str: "YYYY-mm-dd HH:MM"). Defaults to None.
        time_end (str, optional): End time limit of the merged dataset (str: "YYYY-mm-dd HH:MM"). Defaults to None.
        reproject (int, optional): Optionally reproject based, based on EPSG code. Defaults to None.
        local_tz: (Tuple(float, str): optional): Add local timezone format is a tuple with Offset[float] and Label[str]
        source: (str, optional): Ocean data source. Defaults to Hycom.
        wrapto360: (bool, optional): Optionally wrap longitude to (0, 360) rather than (-180, 180). Defaults to False.
    """
    
    args = tuple()

    kwargs = dict(
        in_path=in_path,
        out_path=out_path,
        fname=fname,
        source=source,
        model=model,
        time_start=time_start,
        time_end=time_end,
        reproject=reproject,
        local_tz=local_tz,
        pad_dry=False,
        wrapto360=wrapto360,
    )
    
    if 'write_fvc' in kwargs:
        print('Writing an FVC include file is not implemented for wave data. Skipping this flag')

    if source.lower() == "cawcr":
        from tfv_get_tools.providers.wave.cawcr import MergeCAWCR
        MergeCAWCR(*args, **kwargs)
    
    elif source.lower() == "copernicus":
        from tfv_get_tools.providers.wave.copernicus_wave import MergeCopernicusWave
        MergeCopernicusWave(*args, **kwargs)

    elif source.lower() == "era5":
        from tfv_get_tools.providers.wave.era5 import MergeERA5Wave
        MergeERA5Wave(*args, **kwargs)