# Copyright (C) 2018  Entr'ouvert
#
# 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/>.

import contextlib
import json
import os
import stat
import tempfile

from django.core.files.storage import default_storage
from django.template.loader import get_template
from django.utils.dateparse import parse_date
from django.utils.encoding import force_bytes
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _

from passerelle.base.models import BaseResource
from passerelle.utils.api import endpoint
from passerelle.utils.conversion import ensure_encoding
from passerelle.utils.jsonresponse import APIError


@contextlib.contextmanager
def named_tempfile(*args, **kwargs):
    with tempfile.NamedTemporaryFile(*args, **kwargs) as fp:
        yield fp


class ActesWeb(BaseResource):
    category = _('Civil Status Connectors')

    class Meta:
        verbose_name = "ActesWeb - Demande d'acte d'état civil"

    @property
    def basepath(self):
        return os.path.join(default_storage.path('actesweb'), self.slug)

    @endpoint(perm='can_access', methods=['post'], description=_('Create demand'))
    def create(self, request, *args, **kwargs):
        try:
            payload = json.loads(request.body)
        except (ValueError,):
            raise APIError('Invalid payload format: json expected')

        if payload.get('certificate_type') not in ('NA', 'DE', 'MA'):
            raise APIError("Invalid <certificate_type>: expected ('NA', 'DE', 'MA')")
        payload['event_date_start'] = parse_date(payload['event_date_start']).strftime('%Y%m%d')
        template_name = 'actesweb/demand.txt'
        demand_content = get_template(template_name).render(payload)
        application_id = payload['application_id']
        # create tmp dir
        tmp_dir = os.path.join(self.basepath, 'tmp')
        if not os.path.exists(tmp_dir):
            if default_storage.directory_permissions_mode:
                d_umask = os.umask(0)
                try:
                    os.makedirs(tmp_dir, mode=default_storage.directory_permissions_mode)
                except OSError:
                    pass
                finally:
                    os.umask(d_umask)
            else:
                os.makedirs(tmp_dir)

        # ensure demand_content can be encoded to latin15
        demand_content = ensure_encoding(demand_content, 'iso-8859-15')

        filename = '%s.DEM' % now().strftime('%Y-%m-%d_%H-%M-%S_%f')
        filepath = os.path.join(self.basepath, filename)
        with named_tempfile(dir=tmp_dir, suffix='.DEM', delete=False) as tpf:
            tpf.write(force_bytes(demand_content, 'iso-8859-15'))
            tpf.flush()
            os.fsync(tpf.file.fileno())
            tempfile_name = tpf.name
        os.rename(tempfile_name, filepath)
        # set read only permission for owner and group
        os.chmod(filepath, stat.S_IRUSR | stat.S_IRGRP | stat.S_IWGRP)
        demand_id = '%s_%s' % (application_id, os.path.basename(filepath))
        return {'data': {'demand_id': demand_id}}
