from odoo import models, api, fields, _
from odoo.exceptions import UserError
from datetime import datetime


class CrmLead(models.Model):
    _inherit = 'crm.lead'

    # mapping between the xml_ids related to crm.lead.tag_ids and cm.filter xmlids
    _XMLID_MAPPING_LEADTAGS_CMFILTERS = [
        ('ce_tag_common_generation','ce_cm_filter_community_renewal_generation'),
        ('ce_tag_energy_efficiency','ce_cm_filter_energetic_eficiency'),
        ('ce_tag_sustainable_mobility','ce_cm_filter_sustainable_mobility'),
        ('ce_tag_citizen_education','ce_cm_filter_citizen_education'),
        ('ce_tag_thermal_energy','ce_cm_filter_thermical_energy'),
        ('ce_tag_collective_purchases','ce_cm_filter_collective_purchase'),
        ('ce_tag_renewable_energy','ce_cm_filter_renewal_energy_supply'),
        ('ce_tag_aggregate_demand','ce_cm_filter_demand_flexibility_and_aggregation')
    ]

    lang = fields.Char(string="Language")
    ce_tag_ids = fields.Many2many('crm.tag', 'crm_lead_ce_tag_rel', 'lead_id', 'tag_id', string='CE Tags', help="CE Classify and analyze categories")

    community_company_id = fields.Many2one(
        string='Related Community',
        comodel_name='res.company',
        domain="[('coordinator','!=',True)]",
        help="Community related to this Lead"
    )

    
    def _create_map_place_proposal(self):

        if not self.env.user.company_id.coordinator:
            raise UserError(
                _("Only users that belongs to the 'Coordinator' company can create new Map Places from Leads."))

        active_categ_id = self.env['ir.model.data'].get_object_reference('ce', 'ce_cm_place_category_active')[1]
        building_categ_id = self.env['ir.model.data'].get_object_reference('ce', 'ce_cm_place_category_building')[1]
        default_ce_map_id = self.env['ir.model.data'].get_object_reference('ce', 'ce_default_cm_map')[1]
        creation_ce_source_id = self.env['ir.model.data'].get_object_reference('ce', 'ce_source_creation_ce_proposal')[1]

        for lead in self:

            if self.env['crm.team'].search([('proposal_form_submission_id','=',lead.id), ('map_id','=',default_ce_map_id)]):
                raise UserError(
                    _("There is an allready existing Map Place related to this Lead: {}.").format(lead.name))

            if not lead.source_id or lead.source_id.id != creation_ce_source_id:
                raise UserError(
                    _("The Source {} of Lead {} do not allow the creation of Map Proposals").format(lead.source_id.name, lead.name))

            place_creation_data = {
                'name': lead.name,
                'map_id': default_ce_map_id,
                'team_type': 'map_place_proposal',
                'user_id': self.env.user.id,
                'proposal_form_submission_id': lead.id,
                'interaction_method': 'external_link',
                'external_link_target': '_top',
            }

            # read metadata key/value pairs
            m_dict = {m.key: m.value for m in lead.form_submission_metadata_ids}

            if m_dict.get('partner_legal_state',False) and m_dict['partner_legal_state']:
                if m_dict['partner_legal_state'] == 'active':
                    place_creation_data['place_category_id'] = active_categ_id
                else:
                    place_creation_data['place_category_id'] = building_categ_id
            else:
                raise UserError(
                    _("Unable to get the Category (mandatory map place field) from Lead: {}").format(lead.name))

            if m_dict.get('partner_latitude',False) and m_dict['partner_latitude']:
                place_creation_data['lat'] = m_dict['partner_latitude']
            else:
                raise UserError(
                    _("Unable to get the Latitude (mandatory map place field) from Lead: {}").format(lead.name))

            if m_dict.get('partner_longitude',False) and m_dict['partner_longitude']:
                place_creation_data['lng'] = m_dict['partner_longitude']
            else:
                raise UserError(
                    _("Unable to get the Longitude (mandatory map place field) from Lead: {}").format(lead.name))

            if m_dict.get('partner_map_place_form_url',False) and m_dict['partner_map_place_form_url']:
                place_creation_data['external_link_url'] = m_dict['partner_map_place_form_url']

            place_creation_data['address_txt'] = lead._get_address_txt() or None
            place_creation_data['filter_mids'] = [(6,0,lead._get_cmfilter_ids())]

            place = self.env['crm.team'].create(place_creation_data)

            # we need to do call those next 2 functions because the @api.onchange('map_id') defined on community_maps module
            # is not being called on crm_team.create(). TODO: review why it happens and fix it.
            place._get_slug_id()
            place._get_config_relations_attrs()
            place._build_presenter_metadata_ids()
            place.place_category_id = place_creation_data['place_category_id']

            place.message_subscribe([self.env.user.partner_id.id])

            pmnd_ids = [m for m in place.place_presenter_metadata_ids if m.key == 'p_description']
            description_pmnd_id = pmnd_ids and pmnd_ids[0] or None
            if description_pmnd_id and lead.description:
                description_pmnd_id.value = "<p class='m-2'>{}</p>".format(lead.description)

            # lead update
            lead.write({
                'team_id': place.id,
                'submission_type': 'place_proposal_submission',
            })

    
    def _get_cmfilter_ids(self):
        self.ensure_one()

        md = self.env['ir.model.data']
        id_pairs = {}
        for pair in self._XMLID_MAPPING_LEADTAGS_CMFILTERS:
            id_pairs[md.get_object_reference('ce', pair[0])[1]] = md.get_object_reference('ce', pair[1])[1]

        return [id_pairs[t.id] for t in self.tag_ids if t.id in id_pairs]

    
    def _get_address_txt(self):
        self.ensure_one()

        ret = ''
        meta_address_txt = [meta.value for meta in self.form_submission_metadata_ids if meta.key == 'partner_full_address']

        if self.street and (self.city or self.zip):
            ret ="{}{}. {}{}".format(
                self.street,
                (self.street2 and ' '+self.street2) or '',
                self.zip or '',
                (self.city and ' '+self.city) or '')
            if self.state_id:
                ret += ', {}'.format(self.state_id.name)
            if self.country_id:
                ret += '. {}'.format(self.country_id.name)
        elif meta_address_txt and meta_address_txt[0]:
            ret = meta_address_txt[0]

        return ret

    
    def _build_community_company(self):

        if not self.env.user.company_id.coordinator:
            raise UserError(
                _("Only users that belongs to the 'Coordinator' company can create new Companies from Leads."))

        creation_ce_source_id = self.env['ir.model.data'].get_object_reference('ce', 'ce_source_creation_ce_proposal')[1]

        # build company for each Lead
        for lead in self:

            if not lead.source_id or lead.source_id.id != creation_ce_source_id:
                raise UserError(
                    _("The Source {} of Lead {} do not allow the creation of new Companies").format(lead.source_id.name, lead.name))

            if not lead.community_company_id:
                # Create the new company using very basic starting Data
                company = self.env['res.company'].create(lead._get_company_create_vals())

                # Update Lead & Map Place (if exist) fields accordingly
                lead.community_company_id = company.id
                if lead.team_id and lead.team_type == 'map_place_proposal':
                    lead.team_id.community_company_id = company.id


        # we need to do this commit before proceed to call KeyCloak API calls to build the related KC realms
        self._cr.commit()

        # build keyKloac realm for each new existing new company
        for lead in self:
            if lead.community_company_id:
                lead.community_company_id._create_keycloak_realm()
                lead.community_company_id._community_post_keycloak_creation_tasks()

    
    def _get_company_create_vals(self):
        self.ensure_one()
        m_dict = {m.key: m.value for m in self.form_submission_metadata_ids}

        foundation_date = None
        if m_dict.get('partner_foundation_date',False) and m_dict['partner_foundation_date']:
            date_formats = ['%Y-%m-%d','%d-%m-%Y','%Y/%m/%d','%d/%m/%Y']
            for date_format in date_formats:
                try:
                    foundation_date = datetime.strptime(m_dict['partner_foundation_date'], date_format)
                except:
                    pass
            if not foundation_date:
                raise UserError(
                    _("The Foundation Date value {} have a non valid format. It must be: yyyy-mm-dd or dd-mm-yyyy or yyyy/mm/dd or dd/mm/yyyy").format(m_dict['partner_foundation_date']))

        initial_share_amount = 0.00
        if m_dict.get('partner_initial_share_amount',False) and m_dict['partner_initial_share_amount'] or None:
            try:
                initial_share_amount = float(m_dict['partner_initial_share_amount'])
            except:
                pass

        lang_id = None
        if m_dict.get('partner_language',False) and m_dict['partner_language'] or None:
            lang_id = self.env['res.lang'].search([('code','=',m_dict['partner_language'])],limit=1)


        create_vals = {
                'name': self.name,
                'street': self.street,
                'street2': self.street2,
                'city':self.city,
                'zip': self.zip,
                'state_id': self.state_id.id,
                'country_id': self.country_id.id,
                'website': self.website,
                'phone': self.phone,
                'email': self.email_from or (m_dict.get('contact_email',False) and m_dict['contact_email']) or None,
                'vat': m_dict.get('partner_vat',False) and m_dict['partner_vat'] or None,
                'social_twitter': m_dict.get('partner_twitter',False) and m_dict['partner_twitter'] or None,
                'social_facebook': m_dict.get('partner_facebook',False) and m_dict['partner_facebook'] or None,
                'social_instagram': m_dict.get('partner_instagram',False) and m_dict['partner_instagram'] or None,
                'social_telegram': m_dict.get('partner_telegram',False) and m_dict['partner_telegram'] or None,
                'create_user': True,
                'foundation_date': foundation_date,
                'initial_subscription_share_amount': initial_share_amount,
                'default_lang_id': lang_id and lang_id.id or None,
            }

        return create_vals


    
    def _create_keycloak_realm(self):
        for lead in self:
            if not lead.community_company_id:
                raise UserError(
                    _("Unable to create the KeyCloack entities from Lead: {}, because it is not yet related to any Community company").format(lead.name))
            lead.community_company_id._create_keycloak_realm()

    def post_template_to_chatter(self, template_id):
        self.message_post_with_template(template_id)
    
    def _create_community_initial_users(self):
        for lead in self:
            pass


class CrmTags(models.Model):
    _inherit = 'crm.tag'

    tag_ext_id = fields.Char('ID Ext tag', compute='compute_ext_id_tag')

    def compute_ext_id_tag(self):
        for record in self:
            res = record.get_external_id()
            record.tag_ext_id = False
            if res.get(record.id):
                record.tag_ext_id = res.get(record.id)