import unittest
from zope.component import queryUtility
from zope.component.hooks import setSite
from zope.interface.verify import verifyClass, verifyObject
from waeup.ikoba.testing import (
    FunctionalLayer, FunctionalTestCase,
    )
from waeup.ikoba.payments.interfaces import (
    IPaymentGatewayService, IPayment, STATE_UNPAID,
    )
from waeup.ikoba.app import Company
from waeup.ikoba.payments.payment import Payer, Payee, Payment
from waeup.ikoba.payments.demo_provider import (
    DemoCreditcardPaymentService, RE_CC_NUMBER, RE_CSC,
    )
from waeup.ikoba.payments.tests.test_payment import FakePayer, FakePayable


class TestDemoProviderHelpers(unittest.TestCase):

    def test_re_cc_number(self):
        # we recognize valid numbers
        assert RE_CC_NUMBER.match('a') is None
        assert RE_CC_NUMBER.match('12345678') is None
        assert RE_CC_NUMBER.match('1234a5678') is None
        assert RE_CC_NUMBER.match('132456789') is not None
        assert RE_CC_NUMBER.match('123456789012345') is not None

    def test_re_csc(self):
        # we recognize security numbers
        assert RE_CSC.match('12') is None
        assert RE_CSC.match('123') is not None
        assert RE_CSC.match('1234') is not None
        assert RE_CSC.match('12345') is None
        assert RE_CSC.match('12A2') is None


class DemoCreditcardPaymentServiceTests(FunctionalTestCase):

    layer = FunctionalLayer

    def setUp(self):
        super(DemoCreditcardPaymentServiceTests, self).setUp()
        self.app = Company()
        self.getRootFolder()['app'] = self.app
        setSite(self.app)

    def test_iface(self):
        # we fullfill all interface contracts
        service = DemoCreditcardPaymentService()
        verifyClass(IPaymentGatewayService, DemoCreditcardPaymentService)
        verifyObject(IPaymentGatewayService, service)

    def test_create_payment(self):
        # we can get payments from payment gateways
        service = DemoCreditcardPaymentService()
        payer, payable, payee = Payer(), FakePayable(), Payee()
        payer.payer_id = u'SOME_PAYER_ID'
        result = service.create_payment(payer, payable, payee)
        assert IPayment.providedBy(result)
        assert result.gateway_service == u'demo_creditcard'
        assert result.state == STATE_UNPAID

    def test_create_payment_honors_payer(self):
        # we inspect payers when creating their payments
        service = DemoCreditcardPaymentService()
        payer, payable, payee = Payer(), FakePayable(), Payee()
        payer.payer_id = u'SOME_PAYER_ID'
        result = service.create_payment(payer, payable, payee)
        assert result.payer_id == payer.payer_id

    def test_get_service_by_utility_name(self):
        # we can get the demo credit card service by its utility name
        service = queryUtility(
            IPaymentGatewayService, name="demo_creditcard")
        assert service is not None

    def test_next_step_invalid_id(self):
        # we cannot go to non-existent payments
        service = DemoCreditcardPaymentService()
        result = service.next_step('not-existent-payment-id')
        assert result == (None, None)

    def test_next_step(self):
        # we are redirected to 'index' in the beginning
        service = DemoCreditcardPaymentService()
        p1 = Payment(FakePayer(), FakePayable())
        self.app['payments']['1'] = p1
        p_id = p1.payment_id
        result = service.next_step(p_id)
        assert result == (p1, 'demo_cc1')
