# Copyright (C) 2018, 2019, 2020, 2021 The Meme Factory, Inc.
# http://www.karlpinc.com/

# This file is part of PGWUI_Upload.
#
# This program is free software: you can redistribute it and/or
# modify it under the terms of the GNU Affero General Public License
# as published by the Free Software Foundation, either version 3 of
# the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License along with this program.  If not, see
# <http://www.gnu.org/licenses/>.
#

# Karl O. Pinc <kop@karlpinc.com>

import logging
import pytest
from pgwui_develop import testing
from pyramid.testing import DummyRequest
from pyramid.threadlocal import get_current_request
from pgwui_common.__init__ import includeme as pgwui_common_includeme
from pgwui_core import constants
from pgwui_upload.__init__ import includeme as pgwui_upload_includeme
from pgwui_upload.views import upload

# Activiate our pytest plugin
pytest_plugins = ("pgwui",)


# Constants
CHANGED_RESPONSE = {
    'db': 'somedb',
    'db_changed': True,
    'filename': 'file',
    'lines': 5,
    'null_rep': 'NULL',
    'table': 'sometable',
    'trim_upload': constants.CHECKED,
    'upload_null': constants.CHECKED,
    'user': 'someuser',
}

UNCHANGED_RESPONSE = {'db_changed': False}

# A "upload form"
UPLOAD_FORM_W_LIT_CHECKED = {'literal_col_headings': True}

HOME_PAGE_SETTINGS = {'type': 'URL',
                      'source': '/'}

DEFAULT_URLS = {'pgwui_upload': '/upload',
                'pgwui_logout': '/logout',
                'home_page': '/'}

mock_init = testing.instance_method_mock_fixture('init')


# Helper classes

class MockUploadEngine():
    def __init__(self, run_result):
        self.run_result = run_result

    def run(self):
        return self.run_result


# Fixtures

@pytest.fixture
def isolate_upload_view(monkeypatch, pyramid_request_config):
    '''Keep upload_view() from calling anything

    Also, have isolate_upload_view(response)
    cause UploadEngine to return the supplied "response".
    '''
    def run(response):
        def upload_engine(*args):
            return MockUploadEngine(response)

        monkeypatch.setattr(upload, 'UploadEngine', upload_engine)

        settings = pyramid_request_config.get_settings()
        settings['pgwui'] = settings.get('pgwui', dict())
        settings['pgwui'].update({'home_page': HOME_PAGE_SETTINGS})
        pgwui_common_includeme(pyramid_request_config)
        pgwui_upload_includeme(pyramid_request_config)
        settings['pgwui'].update({'urls': DEFAULT_URLS})
        pyramid_request_config.add_settings(settings)

    return run


# Tests

# TableUploadHandler()

@pytest.fixture
def neuter_tableuploadhandler(monkeypatch, mock_init):
    '''Make TableUploadHander have no initialization and the given uploadform
    '''
    def run(uploadform, request):
        uh = upload.TableUploadHandler(request)
        mocked_init = mock_init(uh)
        mocked_init.return_value = uh

        monkeypatch.setattr(uh, 'uf', uploadform)

        return uh

    return run


# TableUploadHandler.get_form_column_quoter()

@pytest.fixture
def get_quote_columns(neuter_tableuploadhandler):
    '''Return result of the upload handler's get_form_column_quoter()
    '''
    def run(uploadform, settings):
        request = DummyRequest()
        request.registry.settings = settings

        uh = neuter_tableuploadhandler(uploadform, DummyRequest())
        return uh.quote_columns()

    return run


# log_success()

@pytest.mark.parametrize(
    ('checked',), [
        (constants.CHECKED,),
        (constants.UNCHECKED,)])
def test_log_success(caplog, checked):
    '''A "info" level log message is logged
    '''
    caplog.set_level(logging.DEBUG)

    response = CHANGED_RESPONSE.copy()
    response['csv_checked'] = checked
    upload.log_success(response)

    logs = caplog.record_tuples
    assert len(logs) == 1
    assert logs[0][1] == logging.INFO


mock_log_success = testing.make_mock_fixture(
    upload, 'log_success')


# upload_view()

@pytest.fixture
def undecorate(isolate_upload_view):
    '''Get result and the caplog.record_tuples from the upload_view(),
    removing stuff added by the view decorators
    '''
    def run(response):
        isolate_upload_view(response)
        result = upload.upload_view(get_current_request())
        del result['pgwui']  # Remove variables added by pgwui view decorators

        return result

    return run


def test_upload_view_db_not_changed(undecorate, mock_log_success):
    '''When the db did not change nothing logs'''
    response = UNCHANGED_RESPONSE
    result = undecorate(response)

    assert result == response
    assert mock_log_success.call_count == 0


def test_upload_view_db_changed(undecorate, mock_log_success):
    '''When the db did change from CSV input log_success() is called'''
    response = CHANGED_RESPONSE
    result = undecorate(response)

    assert result == response
    assert mock_log_success.call_count == 1
