from django.db import models
from django.conf import settings
from iching.utils.bz import (
    getDateTimeGodEarthStem, gGodstem, gEarthstem, gEarthElement,
    findGodI, findEarthI, calc10God, findEarthstemGod, calcEarthstem10God, calcEarthEmpty,
    calcLifeNumber, calcLifePalace, calc12ChangSengByGod, gGodstem5Element, calc10YearsFate,
    calcNominalAge, calcYearFate, findGodstem5E, calcFiveElementStrengths
)
from iching.utils.bzshagod import (
    calcBaziShaGods, gShagodNames, gGoodGods, god_at,
    # Day god stem sha gods
    tian_yi_at, taiji_at, lushen_at, wenchang_at, fuxing_at, yangren_at, 
    yinchayangcuo_at, feiren_at, shieda_at, liuxiu_at, jinyu_at,
    # Day earth branch sha gods
    yima_at, taohua_at, jiangxing_at, huagai_at, jiesha_at, wangshen_at, gejiao_at,
    # Month earth branch sha gods
    tian_de_at, yue_de_at, tianyi_at, 
    # Year earth branch sha gods
    hongluan_at, tianxi_at, guchen_at, guashu_at, zaisha_at
)
from datetime import datetime
from django.utils import timezone
from iching.utils.numberpower import NumberPower
from iching.utils.serializers import make_json_serializable
from django.conf import settings as django_settings

class Person(models.Model):
    """Model representing a person whose bazi is calculated."""
    GENDER_CHOICES = [
        ('M', '男'),
        ('F', '女'),
        ('N', '不指定'),
    ]
    
    TWIN_CHOICES = [
        (0, '正常'),
        (1, '双大'),
        (2, '双小'),
    ]
    
    ANALYSIS_STATUS_CHOICES = [
        ('pending', '处理中'),
        ('completed', '已完成'),
        ('error', '错误'),
    ]

    REPORT_STATUS_CHOICES = [
        ('pending', '待处理'),
        ('resolved', '已解决'),
        ('dismissed', '已忽略'),
    ]
    
    REPORT_CATEGORY_CHOICES = [
        ('inappropriate_content', '内容不当'),
        ('inaccurate_analysis', '分析不准确'),
        ('offensive_language', '语言冒犯'),
        ('technical_error', '技术错误'),
        ('other', '其他'),
    ]
    
    name = models.CharField(max_length=100)
    gender = models.CharField(max_length=1, choices=GENDER_CHOICES, default='N', verbose_name='性别')
    birth_date = models.DateField()
    birth_time = models.TimeField(null=True, blank=True)
    twin_type = models.IntegerField(choices=TWIN_CHOICES, null=True, blank=True, default=0, verbose_name='双胞胎选项')
    father_dob = models.DateField(null=True, blank=True, verbose_name='父亲生日')
    mother_dob = models.DateField(null=True, blank=True, verbose_name='母亲生日')
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True)
    ori_user = models.IntegerField(null=True, blank=True, help_text='Original user ID before deletion')
    owner = models.BooleanField(default=False, verbose_name='是否用户本人')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    notes = models.TextField(blank=True)
    bazi_result = models.JSONField(null=True, blank=True, verbose_name='八字结果')
    number_result = models.JSONField(null=True, blank=True, verbose_name='数字能量结果')
    
    # BaZi AI analysis fields
    ai_analysis = models.JSONField(null=True, blank=True, verbose_name='八字AI分析结果')
    analysis_timestamp = models.DateTimeField(null=True, blank=True, verbose_name='八字分析时间')
    analysis_status = models.CharField(max_length=20, choices=ANALYSIS_STATUS_CHOICES, null=True, blank=True, verbose_name='八字分析状态')
    
    # BaZi AI analysis reporting fields
    bazi_analysis_reported = models.BooleanField(default=False, verbose_name='八字分析已举报')
    bazi_report_category = models.CharField(max_length=30, choices=REPORT_CATEGORY_CHOICES, null=True, blank=True, verbose_name='八字分析举报类别')
    bazi_report_message = models.TextField(null=True, blank=True, verbose_name='八字分析举报留言', max_length=1000)
    bazi_report_timestamp = models.DateTimeField(null=True, blank=True, verbose_name='八字分析举报时间')
    bazi_report_status = models.CharField(max_length=20, choices=REPORT_STATUS_CHOICES, null=True, blank=True, verbose_name='分析举报状态')
    bazi_report_admin_notes = models.TextField(null=True, blank=True, verbose_name='八字分析举报管理员备注')
    bazi_report_resolved_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='resolved_bazi_reports', verbose_name='八字分析举报处理人')
    bazi_report_resolved_at = models.DateTimeField(null=True, blank=True, verbose_name='八字分析举报处理时间')
    bazi_report_resolution_email_sent = models.BooleanField(default=False, verbose_name='八字分析举报解决邮件已发送')
    
    # Number AI analysis fields
    number_ai_analysis = models.JSONField(null=True, blank=True, verbose_name='数字AI分析结果')
    number_analysis_timestamp = models.DateTimeField(null=True, blank=True, verbose_name='数字分析时间')
    number_analysis_status = models.CharField(max_length=20, choices=ANALYSIS_STATUS_CHOICES, null=True, blank=True, verbose_name='数字分析状态')
    
    # Number AI analysis reporting fields
    number_analysis_reported = models.BooleanField(default=False, verbose_name='数字分析已举报')
    number_report_category = models.CharField(max_length=30, choices=REPORT_CATEGORY_CHOICES, null=True, blank=True, verbose_name='数字分析举报类别')
    number_report_message = models.TextField(null=True, blank=True, verbose_name='数字分析举报留言', max_length=1000)
    number_report_timestamp = models.DateTimeField(null=True, blank=True, verbose_name='数字分析举报时间')
    number_report_status = models.CharField(max_length=20, choices=REPORT_STATUS_CHOICES, null=True, blank=True, verbose_name='分析举报状态')
    number_report_admin_notes = models.TextField(null=True, blank=True, verbose_name='数字分析举报管理员备注')
    number_report_resolved_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name='resolved_number_reports', verbose_name='数字分析举报处理人')
    number_report_resolved_at = models.DateTimeField(null=True, blank=True, verbose_name='数字分析举报处理时间')
    number_report_resolution_email_sent = models.BooleanField(default=False, verbose_name='数字分析举报解决邮件已发送')
    
    # Track temporary user creation
    created_by_temp_user = models.BooleanField(
        default=False,
        verbose_name='临时用户创建',
        help_text='标识此记录是由临时用户创建'
    )
    # Pairwise relations (owner vs this person) - stored for compact retrieval
    relation_good = models.JSONField(null=True, blank=True, help_text='Compact good reasons vs owner')
    relation_bad = models.JSONField(null=True, blank=True, help_text='Compact bad reasons vs owner')
    relation_good_count = models.IntegerField(default=0)
    relation_bad_count = models.IntegerField(default=0)
    relation_updated_at = models.DateTimeField(null=True, blank=True)
    _skip_bazi_calculation = False

    class Meta:
        ordering = ['-created_at']
        
    def __str__(self):
        return f"{self.name}'s BaZi Chart"
    
    def request_analysis(self, analysis_type='bazi'):
        """
        Request AI analysis for this person's chart.
        Sets the analysis status to pending and prepares for async processing.
        
        Args:
            analysis_type: Type of analysis to perform ('bazi', 'number', 'combined')
        
        Returns:
            bool: True if the analysis request was successfully queued
        """
        # Make sure we have the required data
        if not self.bazi_result:
            return False
            
        # Set status to pending
        self.analysis_status = 'pending'
        self.analysis_timestamp = timezone.now()
        self.save(update_fields=['analysis_status', 'analysis_timestamp'])
        
        # Return True to indicate the analysis was successfully queued
        # Actual processing would happen asynchronously
        return True
    
    def update_analysis_status(self, status, result=None):
        """
        Update the analysis status and store results if provided.
        
        Args:
            status: New status ('pending', 'completed', 'error')
            result: JSON analysis result (if status is 'completed')
        
        Returns:
            bool: True if the update was successful
        """
        if status not in dict(self.ANALYSIS_STATUS_CHOICES):
            return False
            
        self.analysis_status = status
        
        if status == 'completed' and result:
            self.ai_analysis = result
            
        self.analysis_timestamp = timezone.now()
        self.save(update_fields=['analysis_status', 'ai_analysis', 'analysis_timestamp'])
        return True
    
    def get_analysis_data(self):
        """
        Get the complete data needed for AI analysis.
        
        Returns:
            dict: Combined data for analysis including BaZi and personal info
        """
        # Get full BaZi calculation data
        bazi_data = self.calculate_bazi()
        
        # Get number power data if available
        number_data = self.number_result if self.number_result else None
        
        # Combine with personal information
        analysis_data = {
            'personal_info': {
                'name': self.name,
                'gender': self.get_gender_display(),
                'birth_date': self.birth_date.isoformat(),
                'birth_time': self.birth_time.isoformat() if self.birth_time else None,
            },
            'bazi_data': bazi_data,
            'number_data': number_data
        }
        
        return analysis_data
    
    def calculate_bazi(self):
        """Calculate the BaZi chart for this person."""
        if not self.birth_date:
            return None
            
        year = self.birth_date.year
        month = self.birth_date.month
        day = self.birth_date.day
        
        # Only calculate hour pillar if birth_time is provided
        has_hour = bool(self.birth_time)
        if has_hour:
            hour = self.birth_time.hour
            minute = self.birth_time.minute
            second = self.birth_time.second
        else:
            hour = 0
            minute = 0
            second = 0
            
        bazi = getDateTimeGodEarthStem(year, month, day, hour, minute, second)
        
        # Calculate nominal age
        nominal_age = calcNominalAge(year, month, day, hour, minute, second)
        
        # Get the day stem index for 10 gods calculation
        day_stem = None
        if bazi['day']:
            day_stem = bazi['day']['g']
        
        # Calculate empty earth branches based on day stem and branch
        empty_earths = calcEarthEmpty(bazi['day']['g'], bazi['day']['e'])
        
        def process_pillar(pillar, pillar_name):
            if not pillar:
                return None
                
            stem_idx = pillar['g']
            branch_idx = pillar['e']
            stem = gGodstem[stem_idx]
            branch = gEarthstem[branch_idx]
            
            # Get the 5 element for the earth branch in Chinese
            element_map = {
                'wood': '木',
                'fire': '火',
                'earth': '土',
                'metal': '金',
                'water': '水'
            }
            earth_element = gEarthElement[branch_idx]['e']
            
            # Calculate 10 gods relationship against day stem
            ten_god = calc10God(day_stem, stem_idx) if day_stem is not None else None
            
            # Calculate hidden gods and their 10 gods relationships
            hidden_gods = []
            earth_gods = findEarthstemGod(branch_idx)
            
            if earth_gods:
                # Get 10 gods relationships for hidden gods
                hidden_gods_rel = calcEarthstem10God(day_stem, branch_idx)
                
                # Process each hidden god
                for god_idx in earth_gods:
                    god = gGodstem[earth_gods[god_idx]]
                    ten_god_rel = hidden_gods_rel.get(earth_gods[god_idx])
                    hidden_gods.append({
                        'god': god,
                        'ten_god': ten_god_rel
                    })
            
            # Check for emptiness (only for hour, month, and year pillars)
            empty = False
            if pillar_name != 'day':
                empty = branch_idx in empty_earths.values()
            
            # Calculate star luck (星运) using the day stem and this pillar's earth branch
            star_luck_idx = None
            if day_stem is not None:
                star_luck_idx = calc12ChangSengByGod(day_stem, branch_idx)
            
            # Calculate self luck (自坐) using this pillar's own stem and earth branch
            self_luck_idx = calc12ChangSengByGod(stem_idx, branch_idx)
            
            return {
                'god': stem,
                'earth': branch,
                'earth_element': earth_element,
                'ten_god': ten_god,
                'hidden_gods': hidden_gods,
                'empty': empty,
                'god_idx': stem_idx,
                'earth_idx': branch_idx,
                'god_element': gGodstem5Element[stem_idx]['e'],
                'star_luck_idx': star_luck_idx,
                'self_luck_idx': self_luck_idx
            }
        
        # Process each pillar
        year_data = process_pillar(bazi['year'], 'year')
        month_data = process_pillar(bazi['month'], 'month')
        day_data = process_pillar(bazi['day'], 'day')
        hour_data = process_pillar(bazi.get('hour'), 'hour') if has_hour else None
        
        # Calculate all sha gods using the new method
        sha_gods_result = calcBaziShaGods(bazi)
        
        # Calculate five element strengths
        element_strengths = calcFiveElementStrengths(bazi)
        
        # Convert indices to Chinese names and include kindness
        sha_gods = {
            pillar: {
                'gods': [{'name': gShagodNames[idx], 'kindness': kindness} for idx, kindness in gods]
            }
            for pillar, gods in sha_gods_result.items()
        }
        
        # Remove hour pillar sha gods if birth time is not provided
        if not has_hour:
            sha_gods['hour'] = {'gods': []}

        # Calculate life number and life palace - not stored in bazi_result
        life_number = None
        life_palace = None
        life_palace_text = None
        
        if self.gender != 'N':  # Only calculate if gender is specified
            gender_val = 'm' if self.gender == 'M' else 'f'
            life_number = calcLifeNumber(gender_val, year, month, day, hour, minute, second)
            life_palace = calcLifePalace(gender_val, year, month, day, hour, minute, second)
            # Map life palace value to descriptive text
            life_palace_text = "东四命" if life_palace == 0 else "西四命"

        # Calculate 10-year fate if gender is specified
        ten_year_fate = None
        current_column_index = None
        current_10year_data = None
        if self.gender != 'N':
            start_year, direction, days, columns = calc10YearsFate(
                gender_val,
                10,  # 10 columns
                year,
                month,
                day,
                hour,
                minute,
                second
            )
            
            # Get the day stem index for 10 gods calculation
            day_stem_idx = bazi['day']['g']
            
            # Format the columns with Chinese characters and find current column
            formatted_columns = []
            for i, col in enumerate(columns):
                age_start = col['y']
                age_end = age_start + 9
                is_current = age_start <= nominal_age <= age_end
                if is_current:
                    current_column_index = i
                
                # Calculate 10-god relationship against day stem for the god stem
                ten_god = calc10God(day_stem_idx, col['g'])
                
                # Calculate hidden gods and their 10-god relationships for the earth branch
                hidden_gods = []
                earth_gods = findEarthstemGod(col['e'])
                if earth_gods:
                    # Get 10 gods relationships for hidden gods
                    hidden_gods_rel = calcEarthstem10God(day_stem_idx, col['e'])
                    
                    # Process each hidden god
                    for god_idx in earth_gods:
                        god = gGodstem[earth_gods[god_idx]]
                        ten_god_rel = hidden_gods_rel.get(earth_gods[god_idx])
                        hidden_gods.append({
                            'god': god,
                            'ten_god': ten_god_rel
                        })
                
                formatted_columns.append({
                    'age_range': f"{age_start}-{age_end}",
                    'god': gGodstem[col['g']],
                    'earth': gEarthstem[col['e']],
                    'is_current': is_current,
                    'ten_god': ten_god,
                    'hidden_gods': hidden_gods
                })
            
            ten_year_fate = {
                'start_year': start_year,
                'direction': direction,
                'days': days,
                'columns': formatted_columns,
                'current_column_index': current_column_index
            }

            # Extract current 10-year fate data for the main table
            if current_column_index is not None:
                current_10year_data = formatted_columns[current_column_index]

        # Calculate year fate (流年) for previous, current, and next year
        year_fate = None
        current_year = datetime.now().year
        year_fate_columns = calcYearFate(12, current_year - 2)
        
        # Format the year fate columns with Chinese characters and calculate 10-god relationships
        if day_stem is not None:
            formatted_year_fate = []
            current_year_data = None
            
            for column in year_fate_columns:
                year_number = list(column.keys())[0]
                year_fate_data = column[year_number]
                
                is_current_year = year_number == current_year
                
                # Calculate 10-god relationship against day stem for the god stem
                ten_god = calc10God(day_stem, year_fate_data['g'])
                
                # Calculate hidden gods and their 10-god relationships for the earth branch
                hidden_gods = []
                earth_gods = findEarthstemGod(year_fate_data['e'])
                if earth_gods:
                    # Get 10 gods relationships for hidden gods
                    hidden_gods_rel = calcEarthstem10God(day_stem, year_fate_data['e'])
                    
                    # Process each hidden god
                    for god_idx in earth_gods:
                        god = gGodstem[earth_gods[god_idx]]
                        ten_god_rel = hidden_gods_rel.get(earth_gods[god_idx])
                        hidden_gods.append({
                            'god': god,
                            'ten_god': ten_god_rel
                        })
                
                formatted_data = {
                    'year': year_number,
                    'god': gGodstem[year_fate_data['g']],
                    'earth': gEarthstem[year_fate_data['e']],
                    'is_current': is_current_year,
                    'ten_god': ten_god,
                    'hidden_gods': hidden_gods,
                    'god_idx': year_fate_data['g'],
                    'earth_idx': year_fate_data['e']
                }
                
                formatted_year_fate.append(formatted_data)
                if is_current_year:
                    current_year_data = formatted_data
            
            year_fate = {
                'columns': formatted_year_fate
            }

        # Define the list of sha gods to calculate using the new god_at method
        god_list = [
            "tian_yi", "wenchang", "tian_de", "yue_de", "taiji", "yima", "lushen", "taohua", 
            "tianxi", "hongluan", "huagai", "fuxing", "liuxiu", "jinyu", "jiangxing", "tianyi"
        ]
        
        # Calculate sha god locations using the new god_at method
        sha_god_locations = god_at(god_list, bazi)
        
        # Store only the bazi pillars in bazi_result
        bazi_result = {
            'year': {
                'god': year_data['god_idx'],
                'earth': year_data['earth_idx']
            },
            'month': {
                'god': month_data['god_idx'],
                'earth': month_data['earth_idx']
            },
            'day': {
                'god': day_data['god_idx'],
                'earth': day_data['earth_idx']
            }
        }
        
        if hour_data:
            bazi_result['hour'] = {
                'god': hour_data['god_idx'],
                'earth': hour_data['earth_idx']
            }
        
        # Store the bazi result but don't save yet
        self.bazi_result = bazi_result

        # Return the complete result including all calculated data
        return {
            'year': year_data,
            'month': month_data,
            'day': day_data,
            'hour': hour_data,
            'sha_gods': sha_gods,
            'sha_god_locations': sha_god_locations,
            'life_number': life_number,
            'life_palace': life_palace_text,
            'ten_year_fate': ten_year_fate,
            'year_fate': year_fate,
            'current_year': current_year_data,
            'current_10year': current_10year_data,
            'bazi_result': bazi_result,
            'nominal_age': nominal_age,
            'element_strengths': element_strengths
        }

    def calculate_number_result(self):
        """Calculate number_result for this person without saving"""
        if not self.birth_date:
            return None
            
        # Format data for calculate method
        dob = self.birth_date.strftime('%Y-%m-%d')
        
        # Format birth time if available
        dobtime = None
        if self.birth_time:
            dobtime = self.birth_time.strftime('%H:%M')
        
        # Format data for NumberPower.calculate
        np_data = {
            'dob': dob,
            'dobtime': dobtime,
            'twin': self.twin_type,
            'fdob': self.father_dob.strftime('%Y-%m-%d') if self.father_dob else None,
            'mdob': self.mother_dob.strftime('%Y-%m-%d') if self.mother_dob else None,
        }
        
        # Calculate number result
        calculator = NumberPower()
        result = calculator.calculate(np_data)
        
        # Make result JSON serializable
        result = make_json_serializable(result)
        
        return result

    def save(self, *args, **kwargs):
        # Calculate bazi result if needed
        if not getattr(self, '_skip_bazi_calculation', False):
            self._skip_bazi_calculation = True
            self.calculate_bazi()
            self._skip_bazi_calculation = False
            
        # Always recalculate number_result if birth_date is present
        if self.birth_date:
            self.number_result = self.calculate_number_result()
        
        # Save the object with all calculations done
        super().save(*args, **kwargs)

    def can_report_bazi_analysis(self):
        """Check if BaZi analysis can be reported."""
        if not (self.ai_analysis and self.analysis_status == 'completed'):
            return False
        if not self.bazi_analysis_reported:
            return True
        if self.bazi_report_status in ['resolved', 'dismissed']:
            return True
        return False
    
    def can_report_number_analysis(self):
        """Check if Number analysis can be reported."""
        if not (self.number_ai_analysis and self.number_analysis_status == 'completed'):
            return False
        if not self.number_analysis_reported:
            return True
        if self.number_report_status in ['resolved', 'dismissed']:
            return True
        return False
    
    def report_bazi_analysis(self, category, user_message=None, reported_by=None):
        """Report BaZi analysis as inappropriate."""
        if not self.can_report_bazi_analysis():
            return False
        
        # Clear previous admin resolution data if re-reporting a resolved/dismissed entry
        if self.bazi_analysis_reported and self.bazi_report_status in ['resolved', 'dismissed']:
            self.bazi_report_admin_notes = None
            self.bazi_report_resolved_by = None
            self.bazi_report_resolved_at = None
            
        self.bazi_analysis_reported = True
        self.bazi_report_category = category
        self.bazi_report_message = user_message
        self.bazi_report_timestamp = timezone.now()
        self.bazi_report_status = 'pending'
        self.bazi_report_resolution_email_sent = False  # Reset email flag for new report
        self.save(update_fields=[
            'bazi_analysis_reported', 'bazi_report_category', 'bazi_report_message', 
            'bazi_report_timestamp', 'bazi_report_status', 'bazi_report_resolution_email_sent',
            'bazi_report_admin_notes', 'bazi_report_resolved_by', 'bazi_report_resolved_at'
        ])
        return True
    
    def report_number_analysis(self, category, user_message=None, reported_by=None):
        """Report Number analysis as inappropriate."""
        if not self.can_report_number_analysis():
            return False
        
        # Clear previous admin resolution data if re-reporting a resolved/dismissed entry
        if self.number_analysis_reported and self.number_report_status in ['resolved', 'dismissed']:
            self.number_report_admin_notes = None
            self.number_report_resolved_by = None
            self.number_report_resolved_at = None
            
        self.number_analysis_reported = True
        self.number_report_category = category
        self.number_report_message = user_message
        self.number_report_timestamp = timezone.now()
        self.number_report_status = 'pending'
        self.number_report_resolution_email_sent = False  # Reset email flag for new report
        self.save(update_fields=[
            'number_analysis_reported', 'number_report_category', 'number_report_message', 
            'number_report_timestamp', 'number_report_status', 'number_report_resolution_email_sent',
            'number_report_admin_notes', 'number_report_resolved_by', 'number_report_resolved_at'
        ])
        return True
    
    def reset_bazi_analysis(self):
        """Reset BaZi analysis and clear reporting status."""
        self.ai_analysis = None
        self.analysis_timestamp = None
        self.analysis_status = None
        self.bazi_analysis_reported = False
        self.bazi_report_category = None
        self.bazi_report_message = None
        self.bazi_report_timestamp = None
        self.bazi_report_status = None
        self.bazi_report_admin_notes = None
        self.bazi_report_resolved_by = None
        self.bazi_report_resolved_at = None
        self.bazi_report_resolution_email_sent = False
        self.save(update_fields=[
            'ai_analysis', 'analysis_timestamp', 'analysis_status',
            'bazi_analysis_reported', 'bazi_report_category', 'bazi_report_message', 
            'bazi_report_timestamp', 'bazi_report_status', 'bazi_report_admin_notes',
            'bazi_report_resolved_by', 'bazi_report_resolved_at',
            'bazi_report_resolution_email_sent'
        ])
    
    def reset_number_analysis(self):
        """Reset Number analysis and clear reporting status."""
        self.number_ai_analysis = None
        self.number_analysis_timestamp = None
        self.number_analysis_status = None
        self.number_analysis_reported = False
        self.number_report_category = None
        self.number_report_message = None
        self.number_report_timestamp = None
        self.number_report_status = None
        self.number_report_admin_notes = None
        self.number_report_resolved_by = None
        self.number_report_resolved_at = None
        self.number_report_resolution_email_sent = False
        self.save(update_fields=[
            'number_ai_analysis', 'number_analysis_timestamp', 'number_analysis_status',
            'number_analysis_reported', 'number_report_category', 'number_report_message', 
            'number_report_timestamp', 'number_report_status', 'number_report_admin_notes',
            'number_report_resolved_by', 'number_report_resolved_at',
            'number_report_resolution_email_sent'
        ])
