# Generated by Django 5.0.9 on 2026-07-05 15:04

import core.models
import django.core.validators
import django.db.models.deletion
from decimal import Decimal
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
    ]

    operations = [
        migrations.CreateModel(
            name='Category',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=100)),
                ('slug', models.SlugField(blank=True, max_length=120, unique=True)),
                ('category_type', models.CharField(choices=[('property', 'Real Estate / Property'), ('place', 'Place / Point of Interest')], default='place', max_length=20)),
                ('description', models.TextField(blank=True)),
                ('icon', models.CharField(blank=True, help_text="Bootstrap icon class, e.g. 'bi-house-door'.", max_length=50)),
                ('order', models.PositiveIntegerField(default=0)),
                ('is_active', models.BooleanField(default=True)),
                ('parent', models.ForeignKey(blank=True, help_text="Leave blank for a top-level category (e.g. 'Property'). Set for a sub-category (e.g. 'House' under 'Property').", null=True, on_delete=django.db.models.deletion.CASCADE, related_name='children', to='core.category')),
            ],
            options={
                'verbose_name_plural': 'Categories',
                'ordering': ['order', 'name'],
            },
        ),
        migrations.CreateModel(
            name='Listing',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
                ('title', models.CharField(max_length=150)),
                ('slug', models.SlugField(blank=True, max_length=180, unique=True)),
                ('description', models.TextField()),
                ('purpose', models.CharField(choices=[('sale', 'For Sale'), ('rent', 'For Rent'), ('service', 'Service / Visit')], default='service', max_length=20)),
                ('address', models.CharField(max_length=255)),
                ('latitude', models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True)),
                ('longitude', models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True)),
                ('price', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True, validators=[django.core.validators.MinValueValidator(Decimal('0'))])),
                ('price_period', models.CharField(blank=True, choices=[('nightly', 'Per Night'), ('monthly', 'Per Month'), ('yearly', 'Per Year'), ('one_time', 'One-time')], max_length=20)),
                ('currency', models.CharField(choices=[('MWK', 'Malawian Kwacha (MWK)'), ('USD', 'US Dollar (USD)')], default='MWK', max_length=5)),
                ('application_fee', models.DecimalField(blank=True, decimal_places=2, max_digits=12, null=True)),
                ('contact_phone', models.CharField(blank=True, max_length=20)),
                ('contact_email', models.EmailField(blank=True, max_length=254)),
                ('contact_whatsapp', models.CharField(blank=True, max_length=20)),
                ('attributes', models.JSONField(blank=True, default=dict)),
                ('status', models.CharField(choices=[('draft', 'Draft'), ('pending_review', 'Pending Review'), ('active', 'Active'), ('sold', 'Sold'), ('rented', 'Rented'), ('closed', 'Closed'), ('rejected', 'Rejected')], db_index=True, default='pending_review', max_length=20)),
                ('rejection_reason', models.CharField(blank=True, max_length=255)),
                ('is_verified_listing', models.BooleanField(default=False, help_text="Mirrors the lister's KYC verification at time of posting.")),
                ('is_featured', models.BooleanField(default=False)),
                ('featured_until', models.DateTimeField(blank=True, null=True)),
                ('views_count', models.PositiveIntegerField(default=0)),
                ('contact_clicks_count', models.PositiveIntegerField(default=0)),
                ('location_fingerprint', models.CharField(blank=True, db_index=True, max_length=64)),
                ('category', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='listings', to='core.category')),
                ('lister', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='listings', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'ordering': ['-is_featured', '-created_at'],
            },
        ),
        migrations.CreateModel(
            name='InquiryRequest',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('move_in_date', models.DateField(blank=True, null=True)),
                ('budget', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
                ('message', models.TextField(blank=True, max_length=1000)),
                ('status', models.CharField(choices=[('pending', 'Pending'), ('responded', 'Responded'), ('closed', 'Closed')], default='pending', max_length=20)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('requester', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inquiries', to=settings.AUTH_USER_MODEL)),
                ('listing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='inquiries', to='core.listing')),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='Favorite',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorites', to=settings.AUTH_USER_MODEL)),
                ('listing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='favorited_by', to='core.listing')),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='Conversation',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
                ('participants', models.ManyToManyField(related_name='conversations', to=settings.AUTH_USER_MODEL)),
                ('listing', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='conversations', to='core.listing')),
            ],
            options={
                'ordering': ['-updated_at'],
            },
        ),
        migrations.CreateModel(
            name='ListingPhoto',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('image', models.ImageField(upload_to=core.models.listing_photo_path)),
                ('caption', models.CharField(blank=True, max_length=150)),
                ('is_cover', models.BooleanField(default=False)),
                ('order', models.PositiveIntegerField(default=0)),
                ('uploaded_at', models.DateTimeField(auto_now_add=True)),
                ('listing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='photos', to='core.listing')),
            ],
            options={
                'ordering': ['order', 'id'],
            },
        ),
        migrations.CreateModel(
            name='Message',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('body', models.TextField(max_length=3000)),
                ('is_read', models.BooleanField(default=False)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('conversation', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='messages', to='core.conversation')),
                ('sender', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='sent_messages', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'ordering': ['created_at'],
            },
        ),
        migrations.CreateModel(
            name='Notification',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('notification_type', models.CharField(choices=[('new_match', 'New Listing Match'), ('price_drop', 'Price Drop'), ('new_message', 'New Message'), ('review_reply', 'Review Reply'), ('kyc_status', 'KYC Status Update'), ('listing_status', 'Listing Status Update'), ('inquiry', 'New Inquiry'), ('system', 'System')], default='system', max_length=30)),
                ('title', models.CharField(max_length=150)),
                ('body', models.CharField(blank=True, max_length=300)),
                ('link', models.CharField(blank=True, max_length=255)),
                ('is_read', models.BooleanField(default=False)),
                ('created_at', models.DateTimeField(auto_now_add=True, db_index=True)),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='notifications', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='PotentialDuplicate',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('similarity_reason', models.CharField(blank=True, max_length=255)),
                ('is_resolved', models.BooleanField(default=False)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('listing_a', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='duplicate_flags_a', to='core.listing')),
                ('listing_b', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='duplicate_flags_b', to='core.listing')),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='Profile',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('phone', models.CharField(blank=True, max_length=20)),
                ('whatsapp', models.CharField(blank=True, max_length=20)),
                ('avatar', models.ImageField(blank=True, null=True, upload_to=core.models.avatar_path)),
                ('bio', models.TextField(blank=True, max_length=500)),
                ('is_lister', models.BooleanField(default=False)),
                ('is_discoverer', models.BooleanField(default=True)),
                ('account_type', models.CharField(blank=True, choices=[('individual', 'Individual Owner'), ('business', 'Business Owner')], max_length=20)),
                ('id_number', models.CharField(blank=True, max_length=50)),
                ('id_photo', models.ImageField(blank=True, null=True, upload_to=core.models.kyc_document_path)),
                ('business_name', models.CharField(blank=True, max_length=150)),
                ('business_registration_number', models.CharField(blank=True, max_length=100)),
                ('business_address', models.CharField(blank=True, max_length=255)),
                ('representative_id_photo', models.ImageField(blank=True, null=True, upload_to=core.models.kyc_document_path)),
                ('proof_of_ownership', models.FileField(blank=True, null=True, upload_to=core.models.kyc_document_path)),
                ('verification_status', models.CharField(choices=[('unverified', 'Unverified'), ('pending', 'Pending Review'), ('verified', 'Verified'), ('rejected', 'Rejected')], default='unverified', max_length=20)),
                ('verification_notes', models.TextField(blank=True, help_text='Internal admin notes, e.g. reason for rejection.')),
                ('verified_at', models.DateTimeField(blank=True, null=True)),
                ('preferred_language', models.CharField(choices=[('en', 'English'), ('ny', 'Chichewa')], default='en', max_length=5)),
                ('preferred_currency', models.CharField(choices=[('MWK', 'MWK'), ('USD', 'USD')], default='MWK', max_length=5)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('updated_at', models.DateTimeField(auto_now=True)),
                ('preferred_intent', models.ForeignKey(blank=True, help_text="What the user first said they were looking for, e.g. 'Houses for rent'.", null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='core.category')),
                ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL)),
            ],
        ),
        migrations.CreateModel(
            name='Report',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('reason', models.CharField(choices=[('scam', 'Looks like a scam'), ('duplicate', 'Duplicate listing'), ('wrong_info', 'Incorrect information'), ('offensive', 'Offensive content'), ('sold_already', 'Already sold / rented / closed'), ('other', 'Other')], default='other', max_length=30)),
                ('details', models.TextField(blank=True, max_length=1000)),
                ('status', models.CharField(choices=[('pending', 'Pending'), ('reviewed', 'Reviewed'), ('action_taken', 'Action Taken'), ('dismissed', 'Dismissed')], default='pending', max_length=20)),
                ('admin_notes', models.TextField(blank=True)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('listing', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reports', to='core.listing')),
                ('reported_user', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='reports_received', to=settings.AUTH_USER_MODEL)),
                ('reporter', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reports_filed', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='Review',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('rating', models.PositiveSmallIntegerField(validators=[django.core.validators.MinValueValidator(1), django.core.validators.MaxValueValidator(5)])),
                ('comment', models.TextField(blank=True, max_length=1500)),
                ('is_approved', models.BooleanField(default=True)),
                ('is_flagged', models.BooleanField(default=False)),
                ('flag_reason', models.CharField(blank=True, max_length=255)),
                ('lister_reply', models.TextField(blank=True, max_length=1000)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('listing', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to='core.listing')),
                ('reviewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reviews', to=settings.AUTH_USER_MODEL)),
            ],
            options={
                'ordering': ['-created_at'],
            },
        ),
        migrations.CreateModel(
            name='SavedSearch',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('label', models.CharField(blank=True, max_length=100)),
                ('keyword', models.CharField(blank=True, max_length=150)),
                ('min_price', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
                ('max_price', models.DecimalField(blank=True, decimal_places=2, max_digits=14, null=True)),
                ('location_text', models.CharField(blank=True, max_length=255)),
                ('latitude', models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True)),
                ('longitude', models.DecimalField(blank=True, decimal_places=7, max_digits=10, null=True)),
                ('radius_km', models.PositiveIntegerField(default=10)),
                ('verified_only', models.BooleanField(default=False)),
                ('is_active', models.BooleanField(default=True)),
                ('created_at', models.DateTimeField(auto_now_add=True)),
                ('last_notified_at', models.DateTimeField(blank=True, null=True)),
                ('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='core.category')),
                ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='saved_searches', to=settings.AUTH_USER_MODEL)),
            ],
        ),
        migrations.CreateModel(
            name='CategoryField',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.SlugField(help_text="Internal key used to store the value, e.g. 'bedrooms'. No spaces.", max_length=60)),
                ('label', models.CharField(help_text="Label shown to the user, e.g. 'Bedrooms'.", max_length=100)),
                ('field_type', models.CharField(choices=[('text', 'Short text'), ('textarea', 'Long text'), ('number', 'Whole number'), ('decimal', 'Decimal number'), ('boolean', 'Yes / No'), ('choice', 'Single choice'), ('multichoice', 'Multiple choice'), ('date', 'Date'), ('time', 'Time'), ('datetime', 'Date & time'), ('url', 'Link / URL')], default='text', max_length=20)),
                ('choices', models.CharField(blank=True, help_text="Comma-separated options, only used for 'Single choice' / 'Multiple choice' e.g. 'Water,Electricity,WiFi,Parking'.", max_length=500)),
                ('unit', models.CharField(blank=True, help_text="e.g. 'm²', 'acres', 'people'.", max_length=20)),
                ('help_text', models.CharField(blank=True, max_length=200)),
                ('required', models.BooleanField(default=False)),
                ('order', models.PositiveIntegerField(default=0)),
                ('category', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='fields', to='core.category')),
            ],
            options={
                'ordering': ['order', 'id'],
                'unique_together': {('category', 'name')},
            },
        ),
        migrations.AddIndex(
            model_name='listing',
            index=models.Index(fields=['status', 'category'], name='core_listin_status_420507_idx'),
        ),
        migrations.AddIndex(
            model_name='listing',
            index=models.Index(fields=['latitude', 'longitude'], name='core_listin_latitud_0e8ecb_idx'),
        ),
        migrations.AlterUniqueTogether(
            name='favorite',
            unique_together={('user', 'listing')},
        ),
        migrations.AlterUniqueTogether(
            name='potentialduplicate',
            unique_together={('listing_a', 'listing_b')},
        ),
        migrations.AlterUniqueTogether(
            name='review',
            unique_together={('listing', 'reviewer')},
        ),
    ]
