'''
Functions for reading and writing internal application config
'''
import configparser
import copy
import hashlib
import json
import logging
import os
import pathlib
from typing import Optional

import click

from jira_offline import __title__
from jira_offline.config.upgrade import upgrade_schema
from jira_offline.config.user_config import load_user_config
from jira_offline.exceptions import (DeserializeError, FailedConfigUpgrade, UnreadableConfig,
                                     UserConfigAlreadyExists)
from jira_offline.models import AppConfig, Issue, ProjectMeta
from jira_offline.utils import get_field_by_name


logger = logging.getLogger('jira')


def load_config():
    '''
    Load app configuration from local JSON file.
    '''
    config_filepath = get_app_config_filepath()

    config: Optional[AppConfig] = None

    if os.path.exists(config_filepath):
        try:
            with open(config_filepath, encoding='utf8') as f:
                config_json = json.load(f)
        except IsADirectoryError:
            raise UnreadableConfig(f'There is already a directory at {config_filepath}')
        except json.decoder.JSONDecodeError:
            raise UnreadableConfig('Bad JSON in config file!', path=config_filepath)

        upgraded_config = False

        # Upgrade configuration file if version has changed
        if config_json['schema_version'] != AppConfig().schema_version:
            upgraded_config = upgrade_schema(
                config_json, config_json['schema_version'], AppConfig().schema_version
            )

        try:
            config = AppConfig.deserialize(config_json)
        except DeserializeError as e:
            raise UnreadableConfig(e, path=config_filepath)

        # If the config schema was upgraded, persist back to disk immediately
        if upgraded_config:
            config.write_to_disk()

        # Ensure each ProjectMeta instance has a reference to the AppConfig instance
        for p in config.projects.values():
            p.config = config

    if not config:
        config = AppConfig()

    # Load settings from the user config file
    load_user_config(config)

    return config


def get_default_user_config_filepath() -> str:
    '''Return the path to jira-offline USER config file'''
    return os.path.join(
        os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')),
        'jira-offline',
        'jira-offline.ini'
    )


def get_app_config_filepath() -> str:
    '''Return the path to jira-offline app config file'''
    return os.path.join(click.get_app_dir(__title__), 'app.json')


def get_cache_filepath() -> str:
    '''Return the path to jira-offline issues cache file'''
    return os.path.join(click.get_app_dir(__title__), 'issue_cache.feather')

'''
Functions for reading and writing internal application config
'''
import configparser
import copy
import hashlib
import json
import logging
import os
import pathlib
from typing import Optional

import click

from jira_offline import __title__
from jira_offline.config.upgrade import upgrade_schema
from jira_offline.config.user_config import load_user_config
from jira_offline.exceptions import (DeserializeError, FailedConfigUpgrade, UnreadableConfig,
                                     UserConfigAlreadyExists)
from jira_offline.models import AppConfig, Issue, ProjectMeta
from jira_offline.utils import get_field_by_name


logger = logging.getLogger('jira')


def load_config():
    '''
    Load app configuration from local JSON file.
    '''
    config_filepath = get_app_config_filepath()

    config: Optional[AppConfig] = None

    if os.path.exists(config_filepath):
        try:
            with open(config_filepath, encoding='utf8') as f:
                config_json = json.load(f)
        except IsADirectoryError:
            raise UnreadableConfig(f'There is already a directory at {config_filepath}')
        except json.decoder.JSONDecodeError:
            raise UnreadableConfig('Bad JSON in config file!', path=config_filepath)

        upgraded_config = False

        # Upgrade configuration file if version has changed
        if config_json['schema_version'] != AppConfig().schema_version:
            upgraded_config = upgrade_schema(
                config_json, config_json['schema_version'], AppConfig().schema_version
            )

        try:
            config = AppConfig.deserialize(config_json)
        except DeserializeError as e:
            raise UnreadableConfig(e, path=config_filepath)

        # If the config schema was upgraded, persist back to disk immediately
        if upgraded_config:
            config.write_to_disk()

        # Ensure each ProjectMeta instance has a reference to the AppConfig instance
        for p in config.projects.values():
            p.config = config

    if not config:
        config = AppConfig()

    # Load settings from the user config file
    load_user_config(config)

    return config


def get_default_user_config_filepath() -> str:
    '''Return the path to jira-offline USER config file'''
    return os.path.join(
        os.environ.get('XDG_CONFIG_HOME', os.path.join(os.path.expanduser('~'), '.config')),
        'jira-offline',
        'jira-offline.ini'
    )


def get_app_config_filepath() -> str:
    '''Return the path to jira-offline app config file'''
    return os.path.join(click.get_app_dir(__title__), 'app.json')


def get_cache_filepath() -> str:
    '''Return the path to jira-offline issues cache file'''
    return os.path.join(click.get_app_dir(__title__), 'issue_cache.feather')

Functions for reading and writing internal application config Load app configuration from local JSON file. # Upgrade configuration file if version has changed # If the config schema was upgraded, persist back to disk immediately # Ensure each ProjectMeta instance has a reference to the AppConfig instance # Load settings from the user config file Return the path to jira-offline USER config file Return the path to jira-offline app config file Return the path to jira-offline issues cache file