"""
Django management command to import CSV data into the database.
"""
import pandas as pd
import os
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.conf import settings
from apps.analytics.models import (
    Broker, Developer, Project, Land, Transaction, Valuation, Rent
)
from datetime import datetime
import logging

logger = logging.getLogger(__name__)


class Command(BaseCommand):
    help = 'Import CSV data from sample data directory'

    def add_arguments(self, parser):
        parser.add_argument(
            '--data-dir',
            type=str,
            default='sample data',
            help='Directory containing CSV files'
        )
        parser.add_argument(
            '--batch-size',
            type=int,
            default=1000,
            help='Batch size for bulk operations'
        )
        parser.add_argument(
            '--clear-existing',
            action='store_true',
            help='Clear existing data before import'
        )

    def handle(self, *args, **options):
        data_dir = options['data_dir']
        batch_size = options['batch_size']
        clear_existing = options['clear_existing']

        if not os.path.exists(data_dir):
            raise CommandError(f'Data directory {data_dir} does not exist')

        if clear_existing:
            self.stdout.write('Clearing existing data...')
            self.clear_data()

        try:
            self.import_brokers(data_dir, batch_size)
            self.import_developers(data_dir, batch_size)
            self.import_projects(data_dir, batch_size)
            self.import_lands(data_dir, batch_size)
            self.import_transactions(data_dir, batch_size)
            self.import_valuations(data_dir, batch_size)
            self.import_rents(data_dir, batch_size)
            
            self.stdout.write(
                self.style.SUCCESS('Successfully imported all CSV data')
            )
        except Exception as e:
            logger.error(f'Error importing data: {e}')
            raise CommandError(f'Failed to import data: {e}')

    def clear_data(self):
        """Clear existing data from all tables."""
        with transaction.atomic():
            Rent.objects.all().delete()
            Valuation.objects.all().delete()
            Transaction.objects.all().delete()
            Land.objects.all().delete()
            Project.objects.all().delete()
            Developer.objects.all().delete()
            Broker.objects.all().delete()

    def import_brokers(self, data_dir, batch_size):
        """Import brokers data."""
        self.stdout.write('Importing brokers...')
        csv_path = os.path.join(data_dir, 'brokers.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping brokers')
            return

        df = pd.read_csv(csv_path)
        brokers = []
        
        for _, row in df.iterrows():
            try:
                broker = Broker(
                    broker_number=str(row['BROKER_NUMBER']),
                    broker_name_en=row['BROKER_EN'],
                    gender=row['GENDER_EN'],
                    license_start_date=self.parse_datetime(row['LICENSE_START_DATE']),
                    license_end_date=self.parse_datetime(row['LICENSE_END_DATE']),
                    webpage=row['WEBPAGE'] if pd.notna(row['WEBPAGE']) else '',
                    phone=row['PHONE'] if pd.notna(row['PHONE']) else '',
                    fax=row['FAX'] if pd.notna(row['FAX']) else '',
                    real_estate_number=row['REAL_ESTATE_NUMBER'] if pd.notna(row['REAL_ESTATE_NUMBER']) else '',
                    real_estate_name_en=row['REAL_ESTATE_EN'] if pd.notna(row['REAL_ESTATE_EN']) else '',
                )
                brokers.append(broker)
                
                if len(brokers) >= batch_size:
                    Broker.objects.bulk_create(brokers, ignore_conflicts=True)
                    brokers = []
                    
            except Exception as e:
                logger.warning(f'Error importing broker row: {e}')
                continue
        
        if brokers:
            Broker.objects.bulk_create(brokers, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Broker.objects.count()} brokers')

    def import_developers(self, data_dir, batch_size):
        """Import developers data from projects."""
        self.stdout.write('Importing developers...')
        csv_path = os.path.join(data_dir, 'projects.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping developers')
            return

        df = pd.read_csv(csv_path)
        developers = []
        seen_developers = set()
        
        for _, row in df.iterrows():
            try:
                dev_number = str(row['DEVELOPER_NUMBER'])
                if dev_number in seen_developers:
                    continue
                    
                developer = Developer(
                    developer_number=dev_number,
                    developer_name_en=row['DEVELOPER_EN'],
                )
                developers.append(developer)
                seen_developers.add(dev_number)
                
                if len(developers) >= batch_size:
                    Developer.objects.bulk_create(developers, ignore_conflicts=True)
                    developers = []
                    
            except Exception as e:
                logger.warning(f'Error importing developer row: {e}')
                continue
        
        if developers:
            Developer.objects.bulk_create(developers, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Developer.objects.count()} developers')

    def import_projects(self, data_dir, batch_size):
        """Import projects data."""
        self.stdout.write('Importing projects...')
        csv_path = os.path.join(data_dir, 'projects.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping projects')
            return

        df = pd.read_csv(csv_path)
        projects = []
        
        for _, row in df.iterrows():
            try:
                developer = Developer.objects.get(developer_number=str(row['DEVELOPER_NUMBER']))
                
                project = Project(
                    project_number=str(row['PROJECT_NUMBER']),
                    project_name_en=row['PROJECT_EN'],
                    developer=developer,
                    start_date=self.parse_datetime(row['START_DATE']),
                    end_date=self.parse_datetime(row['END_DATE']) if pd.notna(row['END_DATE']) else None,
                    adoption_date=self.parse_datetime(row['ADOPTION_DATE']) if pd.notna(row['ADOPTION_DATE']) else None,
                    project_type=row['PRJ_TYPE_EN'],
                    project_value=self.parse_decimal(row['PROJECT_VALUE']) if pd.notna(row['PROJECT_VALUE']) else None,
                    escrow_account_number=row['ESCROW_ACCOUNT_NUMBER'] if pd.notna(row['ESCROW_ACCOUNT_NUMBER']) else '',
                    project_status=row['PROJECT_STATUS'],
                    percent_completed=self.parse_decimal(row['PERCENT_COMPLETED']) if pd.notna(row['PERCENT_COMPLETED']) else None,
                    inspection_date=self.parse_datetime(row['INSPECTION_DATE']) if pd.notna(row['INSPECTION_DATE']) else None,
                    completion_date=self.parse_datetime(row['COMPLETION_DATE']) if pd.notna(row['COMPLETION_DATE']) else None,
                    description_en=row['DESCRIPTION_EN'] if pd.notna(row['DESCRIPTION_EN']) else '',
                    area_en=row['AREA_EN'],
                    zone_en=row['ZONE_EN'],
                    count_land=int(row['CNT_LAND']) if pd.notna(row['CNT_LAND']) else 0,
                    count_building=int(row['CNT_BUILDING']) if pd.notna(row['CNT_BUILDING']) else 0,
                    count_villa=int(row['CNT_VILLA']) if pd.notna(row['CNT_VILLA']) else 0,
                    count_unit=int(row['CNT_UNIT']) if pd.notna(row['CNT_UNIT']) else 0,
                    master_project_en=row['MASTER_PROJECT_EN'] if pd.notna(row['MASTER_PROJECT_EN']) else '',
                )
                projects.append(project)
                
                if len(projects) >= batch_size:
                    Project.objects.bulk_create(projects, ignore_conflicts=True)
                    projects = []
                    
            except Exception as e:
                logger.warning(f'Error importing project row: {e}')
                continue
        
        if projects:
            Project.objects.bulk_create(projects, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Project.objects.count()} projects')

    def import_lands(self, data_dir, batch_size):
        """Import lands data."""
        self.stdout.write('Importing lands...')
        csv_path = os.path.join(data_dir, 'lands.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping lands')
            return

        df = pd.read_csv(csv_path)
        lands = []
        
        for _, row in df.iterrows():
            try:
                project = None
                if pd.notna(row['PROJECT_NUMBER']):
                    try:
                        project = Project.objects.get(project_number=str(row['PROJECT_NUMBER']))
                    except Project.DoesNotExist:
                        pass
                
                land = Land(
                    land_type=row['LAND_TYPE_EN'],
                    property_sub_type=row['PROP_SUB_TYPE_EN'],
                    actual_area=self.parse_decimal(row['ACTUAL_AREA']),
                    is_offplan=row['IS_OFFPLAN_EN'],
                    pre_registration_number=row['PRE_REGISTRATION_NUMBER'] if pd.notna(row['PRE_REGISTRATION_NUMBER']) else '',
                    is_freehold=row['IS_FREE_HOLD_EN'],
                    dm_zip_code=row['DM_ZIP_CODE'] if pd.notna(row['DM_ZIP_CODE']) else '',
                    master_project=row['MASTER_PROJECT_EN'] if pd.notna(row['MASTER_PROJECT_EN']) else '',
                    project=project,
                    area_en=row['AREA_EN'],
                    zone_en=row['ZONE_EN'],
                )
                lands.append(land)
                
                if len(lands) >= batch_size:
                    Land.objects.bulk_create(lands, ignore_conflicts=True)
                    lands = []
                    
            except Exception as e:
                logger.warning(f'Error importing land row: {e}')
                continue
        
        if lands:
            Land.objects.bulk_create(lands, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Land.objects.count()} lands')

    def import_transactions(self, data_dir, batch_size):
        """Import transactions data."""
        self.stdout.write('Importing transactions...')
        csv_path = os.path.join(data_dir, 'transactions.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping transactions')
            return

        df = pd.read_csv(csv_path)
        transactions = []
        
        for _, row in df.iterrows():
            try:
                project = None
                if pd.notna(row['PROJECT_EN']):
                    try:
                        project = Project.objects.get(project_name_en=row['PROJECT_EN'])
                    except Project.DoesNotExist:
                        pass
                
                transaction = Transaction(
                    transaction_number=row['TRANSACTION_NUMBER'],
                    instance_date=self.parse_datetime(row['INSTANCE_DATE']),
                    group=row['GROUP_EN'],
                    procedure=row['PROCEDURE_EN'],
                    is_offplan=row['IS_OFFPLAN_EN'],
                    is_freehold=row['IS_FREE_HOLD_EN'],
                    usage=row['USAGE_EN'],
                    area_en=row['AREA_EN'],
                    property_type=row['PROP_TYPE_EN'],
                    property_sub_type=row['PROP_SB_TYPE_EN'],
                    transaction_value=self.parse_decimal(row['TRANS_VALUE']),
                    procedure_area=self.parse_decimal(row['PROCEDURE_AREA']),
                    actual_area=self.parse_decimal(row['ACTUAL_AREA']),
                    rooms=row['ROOMS_EN'] if pd.notna(row['ROOMS_EN']) else '',
                    parking=row['PARKING'] if pd.notna(row['PARKING']) else '',
                    nearest_metro=row['NEAREST_METRO_EN'] if pd.notna(row['NEAREST_METRO_EN']) else '',
                    nearest_mall=row['NEAREST_MALL_EN'] if pd.notna(row['NEAREST_MALL_EN']) else '',
                    nearest_landmark=row['NEAREST_LANDMARK_EN'] if pd.notna(row['NEAREST_LANDMARK_EN']) else '',
                    total_buyer=int(row['TOTAL_BUYER']) if pd.notna(row['TOTAL_BUYER']) else 0,
                    total_seller=int(row['TOTAL_SELLER']) if pd.notna(row['TOTAL_SELLER']) else 0,
                    master_project=row['MASTER_PROJECT_EN'] if pd.notna(row['MASTER_PROJECT_EN']) else '',
                    project=project,
                )
                transactions.append(transaction)
                
                if len(transactions) >= batch_size:
                    Transaction.objects.bulk_create(transactions, ignore_conflicts=True)
                    transactions = []
                    
            except Exception as e:
                logger.warning(f'Error importing transaction row: {e}')
                continue
        
        if transactions:
            Transaction.objects.bulk_create(transactions, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Transaction.objects.count()} transactions')

    def import_valuations(self, data_dir, batch_size):
        """Import valuations data."""
        self.stdout.write('Importing valuations...')
        csv_path = os.path.join(data_dir, 'valuations.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping valuations')
            return

        df = pd.read_csv(csv_path)
        valuations = []
        
        for _, row in df.iterrows():
            try:
                valuation = Valuation(
                    property_total_value=self.parse_decimal(row['PROPERTY_TOTAL_VALUE']),
                    area_en=row['AREA_EN'],
                    actual_area=self.parse_decimal(row['ACTUAL_AREA']),
                    procedure_year=int(row['PROCEDURE_YEAR']),
                    procedure_number=str(row['PROCEDURE_NUMBER']),
                    instance_date=self.parse_datetime(row['INSTANCE_DATE']),
                    actual_worth=self.parse_decimal(row['ACTUAL_WORTH']),
                    procedure_area=self.parse_decimal(row['PROCEDURE_AREA']),
                    property_type=row['PROPERTY_TYPE_EN'],
                    property_sub_type=row['PROP_SUB_TYPE_EN'],
                )
                valuations.append(valuation)
                
                if len(valuations) >= batch_size:
                    Valuation.objects.bulk_create(valuations, ignore_conflicts=True)
                    valuations = []
                    
            except Exception as e:
                logger.warning(f'Error importing valuation row: {e}')
                continue
        
        if valuations:
            Valuation.objects.bulk_create(valuations, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Valuation.objects.count()} valuations')

    def import_rents(self, data_dir, batch_size):
        """Import rents data."""
        self.stdout.write('Importing rents...')
        csv_path = os.path.join(data_dir, 'rents.csv')
        
        if not os.path.exists(csv_path):
            self.stdout.write(f'Warning: {csv_path} not found, skipping rents')
            return

        df = pd.read_csv(csv_path)
        rents = []
        
        for _, row in df.iterrows():
            try:
                project = None
                if pd.notna(row['PROJECT_EN']):
                    try:
                        project = Project.objects.get(project_name_en=row['PROJECT_EN'])
                    except Project.DoesNotExist:
                        pass
                
                rent = Rent(
                    registration_date=self.parse_datetime(row['REGISTRATION_DATE']),
                    start_date=self.parse_datetime(row['START_DATE']),
                    end_date=self.parse_datetime(row['END_DATE']),
                    version=row['VERSION_EN'],
                    area_en=row['AREA_EN'],
                    contract_amount=self.parse_decimal(row['CONTRACT_AMOUNT']),
                    annual_amount=self.parse_decimal(row['ANNUAL_AMOUNT']),
                    is_freehold=row['IS_FREE_HOLD_EN'],
                    actual_area=self.parse_decimal(row['ACTUAL_AREA']),
                    property_type=row['PROP_TYPE_EN'],
                    property_sub_type=row['PROP_SUB_TYPE_EN'],
                    rooms=row['ROOMS'] if pd.notna(row['ROOMS']) else '',
                    usage=row['USAGE_EN'],
                    nearest_metro=row['NEAREST_METRO_EN'] if pd.notna(row['NEAREST_METRO_EN']) else '',
                    nearest_mall=row['NEAREST_MALL_EN'] if pd.notna(row['NEAREST_MALL_EN']) else '',
                    nearest_landmark=row['NEAREST_LANDMARK_EN'] if pd.notna(row['NEAREST_LANDMARK_EN']) else '',
                    parking=row['PARKING'] if pd.notna(row['PARKING']) else '',
                    total_properties=int(row['TOTAL_PROPERTIES']) if pd.notna(row['TOTAL_PROPERTIES']) else 1,
                    master_project=row['MASTER_PROJECT_EN'] if pd.notna(row['MASTER_PROJECT_EN']) else '',
                    project=project,
                )
                rents.append(rent)
                
                if len(rents) >= batch_size:
                    Rent.objects.bulk_create(rents, ignore_conflicts=True)
                    rents = []
                    
            except Exception as e:
                logger.warning(f'Error importing rent row: {e}')
                continue
        
        if rents:
            Rent.objects.bulk_create(rents, ignore_conflicts=True)
        
        self.stdout.write(f'Imported {Rent.objects.count()} rents')

    def parse_datetime(self, value):
        """Parse datetime string."""
        if pd.isna(value) or value == '' or value == 'NULL':
            return None
        
        try:
            # Try different datetime formats
            formats = [
                '%Y-%m-%d %H:%M:%S',
                '%Y-%m-%d',
                '%d/%m/%Y %H:%M:%S',
                '%d/%m/%Y',
            ]
            
            for fmt in formats:
                try:
                    return datetime.strptime(str(value), fmt)
                except ValueError:
                    continue
            
            # If all formats fail, try pandas parsing
            return pd.to_datetime(value)
        except:
            return None

    def parse_decimal(self, value):
        """Parse decimal value."""
        if pd.isna(value) or value == '' or value == 'NULL':
            return None
        
        try:
            return float(value)
        except:
            return None

