"""
Norda Biznes - Database Models
===============================

SQLAlchemy models for PostgreSQL database.

Models:
- User: User accounts with authentication
- Company: Company information
- Category, Service, Competency: Company classifications
- AIChatConversation, AIChatMessage: Chat history
- AIAPICostLog: API cost tracking
- CompanyDigitalMaturity: Digital maturity scores and benchmarking
- CompanyWebsiteAnalysis: Website analysis and SEO metrics
- MaturityAssessment: Historical tracking of maturity scores
- GBPAudit: Google Business Profile audit results
- ITAudit: IT infrastructure audit results
- ITCollaborationMatch: IT collaboration matches between companies
- AIUsageLog, AIUsageDaily, AIRateLimit: AI API usage monitoring
- Announcement: Ogłoszenia i aktualności dla członków

Author: Norda Biznes Development Team
Created: 2025-11-23
Updated: 2026-01-11 (AI Usage Tracking)
"""

import os
import json
from datetime import datetime
from sqlalchemy import create_engine, Column, Integer, String, Text, Boolean, DateTime, ForeignKey, Table, Numeric, Date, Time, TypeDecorator, UniqueConstraint
from sqlalchemy.dialects.postgresql import ARRAY as PG_ARRAY, JSONB as PG_JSONB
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship
from flask_login import UserMixin

# Database configuration
# WARNING: The fallback DATABASE_URL uses a placeholder password.
# Production credentials MUST be set via the DATABASE_URL environment variable.
# NEVER commit real credentials to version control (CWE-798).
DATABASE_URL = os.getenv(
    'DATABASE_URL',
    'postgresql://nordabiz_app:CHANGE_ME@localhost:5432/nordabiz'
)

# Determine if we're using SQLite
IS_SQLITE = DATABASE_URL.startswith('sqlite')


def normalize_social_url(url: str, platform: str = None) -> str:
    """
    Normalize social media URLs to prevent duplicates.

    Handles:
    - www vs non-www (removes www.)
    - http vs https (forces https)
    - Trailing slashes (removes)
    - Platform-specific canonicalization

    Examples:
        normalize_social_url('http://www.facebook.com/inpipl/')
        -> 'https://facebook.com/inpipl'

        normalize_social_url('https://www.instagram.com/user/')
        -> 'https://instagram.com/user'
    """
    if not url:
        return url

    url = url.strip()

    # Force https
    if url.startswith('http://'):
        url = 'https://' + url[7:]
    elif not url.startswith('https://'):
        url = 'https://' + url

    # Remove www. prefix
    url = url.replace('https://www.', 'https://')

    # Remove trailing slash
    url = url.rstrip('/')

    # Platform-specific normalization
    if platform == 'facebook' or 'facebook.com' in url:
        # fb.com -> facebook.com
        url = url.replace('https://fb.com/', 'https://facebook.com/')
        url = url.replace('https://m.facebook.com/', 'https://facebook.com/')

    if platform == 'twitter' or 'twitter.com' in url or 'x.com' in url:
        # x.com -> twitter.com (or vice versa, pick one canonical)
        url = url.replace('https://x.com/', 'https://twitter.com/')

    if platform == 'linkedin' or 'linkedin.com' in url:
        # Remove locale prefix
        url = url.replace('/pl/', '/').replace('/en/', '/')

    return url


class StringArray(TypeDecorator):
    """
    Platform-agnostic array type.
    Uses PostgreSQL ARRAY for PostgreSQL, stores as JSON string for SQLite.
    """
    impl = Text
    cache_ok = True

    def load_dialect_impl(self, dialect):
        if dialect.name == 'postgresql':
            return dialect.type_descriptor(PG_ARRAY(String))
        return dialect.type_descriptor(Text())

    def process_bind_param(self, value, dialect):
        if value is None:
            return None
        if dialect.name == 'postgresql':
            return value
        return json.dumps(value)

    def process_result_value(self, value, dialect):
        if value is None:
            return None
        if dialect.name == 'postgresql':
            return value
        if isinstance(value, list):
            return value
        return json.loads(value)


class JSONBType(TypeDecorator):
    """
    Platform-agnostic JSONB type.
    Uses PostgreSQL JSONB for PostgreSQL, stores as JSON string for SQLite.
    """
    impl = Text
    cache_ok = True

    def load_dialect_impl(self, dialect):
        if dialect.name == 'postgresql':
            return dialect.type_descriptor(PG_JSONB())
        return dialect.type_descriptor(Text())

    def process_bind_param(self, value, dialect):
        if value is None:
            return None
        if dialect.name == 'postgresql':
            return value
        return json.dumps(value)

    def process_result_value(self, value, dialect):
        if value is None:
            return None
        if dialect.name == 'postgresql':
            return value
        if isinstance(value, dict):
            return value
        return json.loads(value)


# Aliases for backwards compatibility
ARRAY = StringArray
JSONB = JSONBType


# Create engine
engine = create_engine(DATABASE_URL, echo=False)
SessionLocal = sessionmaker(bind=engine)
Base = declarative_base()


# ============================================================
# USER MANAGEMENT
# ============================================================

class User(Base, UserMixin):
    """User accounts"""
    __tablename__ = 'users'

    id = Column(Integer, primary_key=True)
    email = Column(String(255), unique=True, nullable=False, index=True)
    password_hash = Column(String(255), nullable=False)
    name = Column(String(255))
    company_nip = Column(String(10))
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=True)
    company = relationship('Company', backref='users', lazy='joined')  # eager load to avoid DetachedInstanceError
    person_id = Column(Integer, ForeignKey('people.id'), nullable=True)
    person = relationship('Person', backref='users', lazy='joined')  # Link to Person (KRS data)
    phone = Column(String(50))

    # Status
    is_active = Column(Boolean, default=True)
    is_verified = Column(Boolean, default=False)
    is_admin = Column(Boolean, default=False)
    is_norda_member = Column(Boolean, default=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    last_login = Column(DateTime)
    verified_at = Column(DateTime)

    # Verification token
    verification_token = Column(String(255))
    verification_token_expires = Column(DateTime)

    # Password reset token
    reset_token = Column(String(255))
    reset_token_expires = Column(DateTime)

    # Account lockout (brute force protection)
    failed_login_attempts = Column(Integer, default=0)
    locked_until = Column(DateTime, nullable=True)

    # Two-Factor Authentication (TOTP)
    totp_secret = Column(String(32), nullable=True)  # Base32 encoded secret
    totp_enabled = Column(Boolean, default=False)
    totp_backup_codes = Column(StringArray, nullable=True)  # Emergency backup codes

    # Privacy settings
    privacy_show_phone = Column(Boolean, default=True)  # If FALSE, phone hidden from other users
    privacy_show_email = Column(Boolean, default=True)  # If FALSE, email hidden from other users

    # Contact preferences
    contact_prefer_email = Column(Boolean, default=True)  # User prefers email contact
    contact_prefer_phone = Column(Boolean, default=True)  # User prefers phone contact
    contact_prefer_portal = Column(Boolean, default=True)  # User prefers portal messages
    contact_note = Column(Text, nullable=True)  # Additional note (e.g. best hours)

    # Relationships
    conversations = relationship('AIChatConversation', back_populates='user', cascade='all, delete-orphan')
    forum_topics = relationship('ForumTopic', back_populates='author', cascade='all, delete-orphan', primaryjoin='User.id == ForumTopic.author_id')
    forum_replies = relationship('ForumReply', back_populates='author', cascade='all, delete-orphan')

    def __repr__(self):
        return f'<User {self.email}>'


# ============================================================
# COMPANY DIRECTORY (existing schema from SQL)
# ============================================================

class Category(Base):
    """Company categories with hierarchical structure"""
    __tablename__ = 'categories'

    id = Column(Integer, primary_key=True)
    name = Column(String(100), nullable=False, unique=True)
    slug = Column(String(100), nullable=False, unique=True)
    description = Column(Text)
    icon = Column(String(50))
    sort_order = Column(Integer, default=0)
    created_at = Column(DateTime, default=datetime.now)

    # Hierarchical structure
    parent_id = Column(Integer, ForeignKey('categories.id'), nullable=True)
    display_order = Column(Integer, default=0)

    # Relationships
    companies = relationship('Company', back_populates='category')
    parent = relationship('Category', remote_side=[id], backref='subcategories')

    @property
    def is_main_category(self):
        """Check if this is a main (parent) category"""
        return self.parent_id is None


class Company(Base):
    """Companies"""
    __tablename__ = 'companies'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False)
    legal_name = Column(String(255))
    slug = Column(String(255), nullable=False, unique=True, index=True)
    category_id = Column(Integer, ForeignKey('categories.id'))

    # Descriptions
    description_short = Column(Text)
    description_full = Column(Text)

    # Legal
    nip = Column(String(10), unique=True)
    regon = Column(String(14))
    krs = Column(String(10))

    # Parent company relationship (for brands/divisions of the same legal entity)
    parent_company_id = Column(Integer, ForeignKey('companies.id'), nullable=True)

    # External registry slugs
    aleo_slug = Column(String(255))  # ALEO.com company slug for direct links

    # Contact
    website = Column(String(500))
    email = Column(String(255))
    phone = Column(String(50))

    # Address
    address_street = Column(String(255))
    address_city = Column(String(100))
    address_postal = Column(String(10))
    address_full = Column(Text)

    # Business data
    year_established = Column(Integer)
    employees_count = Column(Integer)
    capital_amount = Column(Numeric(15, 2))

    # Status (PostgreSQL uses ENUM types, no default here)
    status = Column(String(20))
    data_quality = Column(String(20))

    # Extended company info
    legal_form = Column(String(100))
    parent_organization = Column(String(255))
    industry_sector = Column(String(255))
    services_offered = Column(Text)
    operational_area = Column(String(500))
    languages_offered = Column(String(200))
    technologies_used = Column(Text)
    founding_history = Column(Text)  # Historia firmy + właściciele
    core_values = Column(Text)  # Wartości firmy
    branch_count = Column(Integer)
    employee_count_range = Column(String(50))

    # PKD (kod działalności gospodarczej) - z CEIDG
    pkd_code = Column(String(10))  # np. "6201Z"
    pkd_description = Column(Text)  # np. "Działalność związana z oprogramowaniem"

    # Data rozpoczęcia działalności - z CEIDG
    business_start_date = Column(Date)  # np. 2021-02-10

    # Właściciel JDG - z CEIDG (tylko dla jednoosobowych działalności)
    owner_first_name = Column(String(100))
    owner_last_name = Column(String(100))

    # Data source tracking
    data_source = Column(String(100))
    data_quality_score = Column(Integer)
    last_verified_at = Column(DateTime)
    norda_biznes_url = Column(String(500))
    norda_biznes_member_id = Column(String(50))
    member_since = Column(Date)  # Data przystąpienia do Izby NORDA

    # Metadata
    last_updated = Column(DateTime, default=datetime.now)
    created_at = Column(DateTime, default=datetime.now)

    # === DIGITAL MATURITY (added 2025-11-26) ===
    digital_maturity_last_assessed = Column(DateTime)
    digital_maturity_score = Column(Integer)  # 0-100 composite score
    digital_maturity_rank_category = Column(Integer)
    digital_maturity_rank_overall = Column(Integer)

    # AI Readiness
    ai_enabled = Column(Boolean, default=False)
    ai_tools_used = Column(ARRAY(String))  # PostgreSQL array (will be Text for SQLite)
    data_structured = Column(Boolean, default=False)

    # IT Management
    it_manager_exists = Column(Boolean, default=False)
    it_outsourced = Column(Boolean, default=False)
    it_provider_company_id = Column(Integer, ForeignKey('companies.id'))

    # Website tracking
    website_last_analyzed = Column(DateTime)
    website_status = Column(String(20))  # 'active', 'broken', 'no_website'
    website_quality_score = Column(Integer)  # 0-100

    # === KRS DATA (added 2026-01-13) ===
    krs_registration_date = Column(Date)      # Data wpisu do KRS
    krs_company_agreement_date = Column(Date) # Data umowy spółki
    krs_duration = Column(String(100))        # Czas trwania (NIEOZNACZONY lub data)
    krs_representation_rules = Column(Text)   # Sposób reprezentacji
    capital_currency = Column(String(3), default='PLN')
    capital_shares_count = Column(Integer)    # Liczba udziałów
    capital_share_value = Column(Numeric(15, 2))  # Wartość nominalna udziału
    is_opp = Column(Boolean, default=False)   # Czy OPP
    krs_last_audit_at = Column(DateTime)      # Data ostatniego audytu KRS
    krs_pdf_path = Column(Text)               # Ścieżka do pliku PDF

    # Relationships
    category = relationship('Category', back_populates='companies')
    services = relationship('CompanyService', back_populates='company', cascade='all, delete-orphan')
    competencies = relationship('CompanyCompetency', back_populates='company', cascade='all, delete-orphan')
    certifications = relationship('Certification', back_populates='company', cascade='all, delete-orphan')
    awards = relationship('Award', back_populates='company', cascade='all, delete-orphan')
    events = relationship('CompanyEvent', back_populates='company', cascade='all, delete-orphan')

    # Digital Maturity relationships
    digital_maturity = relationship('CompanyDigitalMaturity', back_populates='company', uselist=False)
    website_analyses = relationship('CompanyWebsiteAnalysis', back_populates='company', cascade='all, delete-orphan')
    maturity_history = relationship('MaturityAssessment', back_populates='company', cascade='all, delete-orphan')

    # Quality tracking
    quality_tracking = relationship('CompanyQualityTracking', back_populates='company', uselist=False)

    # Website scraping and AI analysis
    website_content = relationship('CompanyWebsiteContent', back_populates='company', cascade='all, delete-orphan')
    ai_insights = relationship('CompanyAIInsights', back_populates='company', uselist=False)


class Service(Base):
    """Services offered by companies"""
    __tablename__ = 'services'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False, unique=True)
    slug = Column(String(255), nullable=False, unique=True)
    description = Column(Text)
    created_at = Column(DateTime, default=datetime.now)

    companies = relationship('CompanyService', back_populates='service')


class CompanyService(Base):
    """Many-to-many: Companies <-> Services"""
    __tablename__ = 'company_services'

    company_id = Column(Integer, ForeignKey('companies.id'), primary_key=True)
    service_id = Column(Integer, ForeignKey('services.id'), primary_key=True)
    is_primary = Column(Boolean, default=False)
    added_at = Column(DateTime, default=datetime.now)

    company = relationship('Company', back_populates='services')
    service = relationship('Service', back_populates='companies')


class Competency(Base):
    """Competencies/skills of companies"""
    __tablename__ = 'competencies'

    id = Column(Integer, primary_key=True)
    name = Column(String(255), nullable=False, unique=True)
    slug = Column(String(255), nullable=False, unique=True)
    category = Column(String(100))
    description = Column(Text)
    created_at = Column(DateTime, default=datetime.now)

    companies = relationship('CompanyCompetency', back_populates='competency')


class CompanyCompetency(Base):
    """Many-to-many: Companies <-> Competencies"""
    __tablename__ = 'company_competencies'

    company_id = Column(Integer, ForeignKey('companies.id'), primary_key=True)
    competency_id = Column(Integer, ForeignKey('competencies.id'), primary_key=True)
    level = Column(String(50))
    added_at = Column(DateTime, default=datetime.now)

    company = relationship('Company', back_populates='competencies')
    competency = relationship('Competency', back_populates='companies')


class Certification(Base):
    """Company certifications"""
    __tablename__ = 'certifications'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'))
    name = Column(String(255), nullable=False)
    issuer = Column(String(255))
    certificate_number = Column(String(100))
    issue_date = Column(Date)
    expiry_date = Column(Date)
    is_active = Column(Boolean, default=True)
    created_at = Column(DateTime, default=datetime.now)

    company = relationship('Company', back_populates='certifications')


class Award(Base):
    """Company awards and achievements"""
    __tablename__ = 'awards'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'))
    name = Column(String(255), nullable=False)
    issuer = Column(String(255))
    year = Column(Integer)
    description = Column(Text)
    created_at = Column(DateTime, default=datetime.now)

    company = relationship('Company', back_populates='awards')


class CompanyEvent(Base):
    """Company events and news"""
    __tablename__ = 'company_events'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'))
    event_type = Column(String(50), nullable=False)
    title = Column(String(500), nullable=False)
    description = Column(Text)
    event_date = Column(Date)
    source_url = Column(String(1000))
    created_at = Column(DateTime, default=datetime.now)

    company = relationship('Company', back_populates='events')


# ============================================================
# DIGITAL MATURITY ASSESSMENT PLATFORM
# ============================================================

class CompanyDigitalMaturity(Base):
    """Central dashboard for company digital maturity - composite scores and benchmarking"""
    __tablename__ = 'company_digital_maturity'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, unique=True, index=True)
    last_updated = Column(DateTime, default=datetime.now)

    # === COMPOSITE SCORES (0-100 each) ===
    overall_score = Column(Integer)
    online_presence_score = Column(Integer)
    social_media_score = Column(Integer)
    it_infrastructure_score = Column(Integer)
    business_applications_score = Column(Integer)
    backup_disaster_recovery_score = Column(Integer)
    cybersecurity_score = Column(Integer)
    ai_readiness_score = Column(Integer)
    digital_marketing_score = Column(Integer)

    # === GAPS & OPPORTUNITIES ===
    critical_gaps = Column(ARRAY(String))  # ['no_backup', 'no_firewall', etc.]
    improvement_priority = Column(String(20))  # 'critical', 'high', 'medium', 'low'
    estimated_investment_needed = Column(Numeric(10, 2))  # PLN

    # === BENCHMARKING ===
    rank_in_category = Column(Integer)  # position in category
    rank_overall = Column(Integer)  # overall position
    percentile = Column(Integer)  # top X% of companies

    # === SALES INTELLIGENCE ===
    total_opportunity_value = Column(Numeric(10, 2))  # potential sales value (PLN)
    sales_readiness = Column(String(20))  # 'hot', 'warm', 'cold', 'not_ready'

    # Relationship
    company = relationship('Company', back_populates='digital_maturity')


class CompanyWebsiteAnalysis(Base):
    """Detailed website and online presence analysis"""
    __tablename__ = 'company_website_analysis'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, index=True)
    analyzed_at = Column(DateTime, default=datetime.now, index=True)

    # === BASIC INFO ===
    website_url = Column(String(500))
    final_url = Column(String(500))  # After redirects
    http_status_code = Column(Integer)
    load_time_ms = Column(Integer)

    # === TECHNICAL ===
    has_ssl = Column(Boolean, default=False)
    ssl_expires_at = Column(Date)
    ssl_issuer = Column(String(100))  # Certificate Authority (Let's Encrypt, DigiCert, etc.)
    is_responsive = Column(Boolean, default=False)  # mobile-friendly
    cms_detected = Column(String(100))
    frameworks_detected = Column(ARRAY(String))  # ['WordPress', 'Bootstrap', etc.]

    # === HOSTING & SERVER (from audit) ===
    last_modified_at = Column(DateTime)
    hosting_provider = Column(String(100))
    hosting_ip = Column(String(45))
    server_software = Column(String(100))
    site_author = Column(String(255))  # Website creator/agency
    site_generator = Column(String(100))
    domain_registrar = Column(String(100))
    is_mobile_friendly = Column(Boolean, default=False)
    has_viewport_meta = Column(Boolean, default=False)

    # === GOOGLE BUSINESS (from audit) ===
    google_rating = Column(Numeric(2, 1))
    google_reviews_count = Column(Integer)
    google_place_id = Column(String(100))
    google_business_status = Column(String(50))
    google_opening_hours = Column(JSONB)  # Opening hours from GBP
    google_photos_count = Column(Integer)  # Number of photos on GBP
    google_name = Column(String(255))  # Business name from Google
    google_address = Column(String(500))  # Formatted address from Google
    google_phone = Column(String(50))  # Phone from Google
    google_website = Column(String(500))  # Website from Google
    google_types = Column(ARRAY(Text))  # Business types/categories
    google_maps_url = Column(String(500))  # Google Maps URL

    # === AUDIT METADATA ===
    audit_source = Column(String(50), default='automated')
    audit_version = Column(String(20), default='1.0')
    audit_errors = Column(Text)

    # === CONTENT RICHNESS ===
    content_richness_score = Column(Integer)  # 1-10
    page_count_estimate = Column(Integer)
    word_count_homepage = Column(Integer)
    has_blog = Column(Boolean, default=False)
    has_portfolio = Column(Boolean, default=False)
    has_contact_form = Column(Boolean, default=False)
    has_live_chat = Column(Boolean, default=False)

    # === EXTRACTED CONTENT ===
    content_summary = Column(Text)  # AI-generated summary from website
    services_extracted = Column(ARRAY(String))  # Services mentioned on website
    main_keywords = Column(ARRAY(String))  # Top keywords

    # === SEO ===
    seo_title = Column(String(500))
    seo_description = Column(Text)
    has_sitemap = Column(Boolean, default=False)
    has_robots_txt = Column(Boolean, default=False)
    google_indexed_pages = Column(Integer)

    # === PAGESPEED INSIGHTS SCORES (0-100) ===
    pagespeed_seo_score = Column(Integer)  # Google PageSpeed SEO score 0-100
    pagespeed_performance_score = Column(Integer)  # Google PageSpeed Performance score 0-100
    pagespeed_accessibility_score = Column(Integer)  # Google PageSpeed Accessibility score 0-100
    pagespeed_best_practices_score = Column(Integer)  # Google PageSpeed Best Practices score 0-100
    pagespeed_audits = Column(JSONB)  # Full PageSpeed audit results as JSON

    # === ON-PAGE SEO DETAILS ===
    meta_title = Column(String(500))  # Full meta title from <title> tag
    meta_description = Column(Text)  # Full meta description from <meta name="description">
    meta_keywords = Column(Text)  # Meta keywords (legacy, rarely used)

    # Heading structure
    h1_count = Column(Integer)  # Number of H1 tags on homepage (should be 1)
    h2_count = Column(Integer)  # Number of H2 tags on homepage
    h3_count = Column(Integer)  # Number of H3 tags on homepage
    h1_text = Column(String(500))  # Text content of first H1 tag

    # Image analysis
    total_images = Column(Integer)  # Total number of images
    images_without_alt = Column(Integer)  # Images missing alt attribute - accessibility issue
    images_with_alt = Column(Integer)  # Images with proper alt text

    # Link analysis
    internal_links_count = Column(Integer)  # Links to same domain
    external_links_count = Column(Integer)  # Links to external domains
    broken_links_count = Column(Integer)  # Links returning 4xx/5xx

    # Structured data (Schema.org, JSON-LD, Microdata)
    has_structured_data = Column(Boolean, default=False)  # Whether page contains JSON-LD, Microdata, or RDFa
    structured_data_types = Column(ARRAY(String))  # Schema.org types found: Organization, LocalBusiness, etc.
    structured_data_json = Column(JSONB)  # Full structured data as JSON

    # === TECHNICAL SEO ===
    # Canonical URL handling
    has_canonical = Column(Boolean, default=False)  # Whether page has canonical URL defined
    canonical_url = Column(String(500))  # The canonical URL value

    # Indexability
    is_indexable = Column(Boolean, default=True)  # Whether page can be indexed (no noindex directive)
    noindex_reason = Column(String(200))  # Reason if page is not indexable: meta tag, robots.txt, etc.

    # Core Web Vitals
    viewport_configured = Column(Boolean)  # Whether viewport meta tag is properly configured
    largest_contentful_paint_ms = Column(Integer)  # Core Web Vital: LCP in milliseconds
    first_input_delay_ms = Column(Integer)  # Core Web Vital: FID in milliseconds
    cumulative_layout_shift = Column(Numeric(5, 3))  # Core Web Vital: CLS score

    # Open Graph & Social Meta
    has_og_tags = Column(Boolean, default=False)  # Whether page has Open Graph tags
    og_title = Column(String(500))  # Open Graph title
    og_description = Column(Text)  # Open Graph description
    og_image = Column(String(500))  # Open Graph image URL
    has_twitter_cards = Column(Boolean, default=False)  # Whether page has Twitter Card meta tags

    # Language & International
    html_lang = Column(String(10))  # Language attribute from <html lang="...">
    has_hreflang = Column(Boolean, default=False)  # Whether page has hreflang tags

    # === SEO AUDIT METADATA ===
    seo_audit_version = Column(String(20))  # Version of SEO audit script used
    seo_audited_at = Column(DateTime)  # Timestamp of last SEO audit
    seo_audit_errors = Column(ARRAY(String))  # Errors encountered during SEO audit
    seo_overall_score = Column(Integer)  # Calculated overall SEO score 0-100
    seo_health_score = Column(Integer)  # On-page SEO health score 0-100
    seo_issues = Column(JSONB)  # List of SEO issues found with severity levels

    # === DOMAIN ===
    domain_registered_at = Column(Date)
    domain_expires_at = Column(Date)
    domain_age_years = Column(Integer)

    # === ANALYTICS ===
    has_google_analytics = Column(Boolean, default=False)
    has_google_tag_manager = Column(Boolean, default=False)
    has_facebook_pixel = Column(Boolean, default=False)

    # === OPPORTUNITY SCORING ===
    needs_redesign = Column(Boolean, default=False)
    missing_features = Column(ARRAY(String))  # ['blog', 'portfolio', 'ssl', etc.]
    opportunity_score = Column(Integer)  # 0-100
    estimated_project_value = Column(Numeric(10, 2))  # PLN
    opportunity_notes = Column(Text)

    # Relationship
    company = relationship('Company', back_populates='website_analyses')


class CompanyQualityTracking(Base):
    """Quality tracking for company data - verification counter and quality score"""
    __tablename__ = 'company_quality_tracking'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, unique=True, index=True)
    verification_count = Column(Integer, default=0)
    last_verified_at = Column(DateTime)
    verified_by = Column(String(100))
    verification_notes = Column(Text)
    quality_score = Column(Integer)  # 0-100%
    issues_found = Column(Integer, default=0)
    issues_fixed = Column(Integer, default=0)
    created_at = Column(DateTime, default=datetime.utcnow)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relationship
    company = relationship('Company', back_populates='quality_tracking')


class CompanyWebsiteContent(Base):
    """Scraped website content for companies"""
    __tablename__ = 'company_website_content'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, index=True)
    scraped_at = Column(DateTime, default=datetime.utcnow)
    url = Column(String(500))
    http_status = Column(Integer)
    raw_html = Column(Text)
    raw_text = Column(Text)
    page_title = Column(String(500))
    meta_description = Column(Text)
    main_content = Column(Text)
    email_addresses = Column(ARRAY(String))
    phone_numbers = Column(ARRAY(String))
    social_media = Column(JSONB)
    word_count = Column(Integer)

    # Relationship
    company = relationship('Company', back_populates='website_content')


class CompanyAIInsights(Base):
    """AI-generated insights from website analysis"""
    __tablename__ = 'company_ai_insights'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, unique=True, index=True)
    content_id = Column(Integer, ForeignKey('company_website_content.id'))
    business_summary = Column(Text)
    services_list = Column(ARRAY(String))
    target_market = Column(Text)
    unique_selling_points = Column(ARRAY(String))
    company_values = Column(ARRAY(String))
    certifications = Column(ARRAY(String))
    suggested_category = Column(String(100))
    category_confidence = Column(Numeric(3, 2))
    industry_tags = Column(ARRAY(String))
    ai_confidence_score = Column(Numeric(3, 2))
    processing_time_ms = Column(Integer)
    analyzed_at = Column(DateTime, default=datetime.utcnow)

    # Relationship
    company = relationship('Company', back_populates='ai_insights')


class MaturityAssessment(Base):
    """Historical tracking of digital maturity scores over time"""
    __tablename__ = 'maturity_assessments'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=False, index=True)
    assessed_at = Column(DateTime, default=datetime.now, index=True)
    assessed_by_user_id = Column(Integer, ForeignKey('users.id'))
    assessment_type = Column(String(50))  # 'full', 'quick', 'self_reported', 'audit'

    # === SNAPSHOT OF SCORES ===
    overall_score = Column(Integer)
    online_presence_score = Column(Integer)
    social_media_score = Column(Integer)
    it_infrastructure_score = Column(Integer)
    business_applications_score = Column(Integer)
    backup_dr_score = Column(Integer)
    cybersecurity_score = Column(Integer)
    ai_readiness_score = Column(Integer)

    # === CHANGES SINCE LAST ASSESSMENT ===
    score_change = Column(Integer)  # +5, -3, etc.
    areas_improved = Column(ARRAY(String))  # ['cybersecurity', 'backup']
    areas_declined = Column(ARRAY(String))  # ['social_media']

    notes = Column(Text)

    # Relationship
    company = relationship('Company', back_populates='maturity_history')


# ============================================================
# AI CHAT
# ============================================================

class AIChatConversation(Base):
    """Chat conversations"""
    __tablename__ = 'ai_chat_conversations'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False, index=True)
    title = Column(String(255))
    conversation_type = Column(String(50), default='general')

    # Timestamps
    started_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)
    is_active = Column(Boolean, default=True)

    # Metrics
    message_count = Column(Integer, default=0)
    model_name = Column(String(100))

    # Relationships
    user = relationship('User', back_populates='conversations')
    messages = relationship('AIChatMessage', back_populates='conversation', cascade='all, delete-orphan', order_by='AIChatMessage.created_at')


class AIChatMessage(Base):
    """Chat messages"""
    __tablename__ = 'ai_chat_messages'

    id = Column(Integer, primary_key=True)
    conversation_id = Column(Integer, ForeignKey('ai_chat_conversations.id'), nullable=False, index=True)
    created_at = Column(DateTime, default=datetime.now)

    # Message
    role = Column(String(20), nullable=False)  # 'user' or 'assistant'
    content = Column(Text, nullable=False)

    # Metrics
    tokens_input = Column(Integer)
    tokens_output = Column(Integer)
    cost_usd = Column(Numeric(10, 6))
    latency_ms = Column(Integer)

    # Flags
    edited = Column(Boolean, default=False)
    regenerated = Column(Boolean, default=False)

    # Feedback (for assistant messages)
    feedback_rating = Column(Integer)  # 1 = thumbs down, 2 = thumbs up
    feedback_comment = Column(Text)  # Optional user comment
    feedback_at = Column(DateTime)

    # Quality metrics (for analytics)
    companies_mentioned = Column(Integer)  # Number of companies in response
    query_intent = Column(String(100))  # Detected intent: 'find_company', 'get_info', 'compare', etc.

    # Relationship
    conversation = relationship('AIChatConversation', back_populates='messages')
    feedback = relationship('AIChatFeedback', back_populates='message', uselist=False)


class AIChatFeedback(Base):
    """Detailed feedback for AI responses - for learning and improvement"""
    __tablename__ = 'ai_chat_feedback'

    id = Column(Integer, primary_key=True)
    message_id = Column(Integer, ForeignKey('ai_chat_messages.id'), nullable=False, unique=True)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    created_at = Column(DateTime, default=datetime.now)

    # Rating
    rating = Column(Integer, nullable=False)  # 1-5 stars or 1=bad, 2=good
    is_helpful = Column(Boolean)  # Was the answer helpful?
    is_accurate = Column(Boolean)  # Was the information accurate?
    found_company = Column(Boolean)  # Did user find what they were looking for?

    # Feedback text
    comment = Column(Text)
    suggested_answer = Column(Text)  # What should have been the answer?

    # Context for learning
    original_query = Column(Text)  # The user's question
    expected_companies = Column(Text)  # JSON list of company names user expected

    # Relationship
    message = relationship('AIChatMessage', back_populates='feedback')


# ============================================================
# FORUM
# ============================================================

class ForumTopic(Base):
    """Forum topics/threads"""
    __tablename__ = 'forum_topics'

    id = Column(Integer, primary_key=True)
    title = Column(String(255), nullable=False)
    content = Column(Text, nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'), nullable=False)

    # Category and Status (for feedback tracking)
    category = Column(String(50), default='question')  # feature_request, bug, question, announcement
    status = Column(String(50), default='new')  # new, in_progress, resolved, rejected
    status_changed_by = Column(Integer, ForeignKey('users.id'))
    status_changed_at = Column(DateTime)
    status_note = Column(Text)

    # Moderation flags
    is_pinned = Column(Boolean, default=False)
    is_locked = Column(Boolean, default=False)
    is_ai_generated = Column(Boolean, default=False)
    views_count = Column(Integer, default=0)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Constants for validation
    CATEGORIES = ['feature_request', 'bug', 'question', 'announcement', 'test']
    STATUSES = ['new', 'in_progress', 'resolved', 'rejected']

    CATEGORY_LABELS = {
        'feature_request': 'Propozycja funkcji',
        'bug': 'Błąd',
        'question': 'Pytanie',
        'announcement': 'Ogłoszenie',
        'test': 'Testowy'
    }

    STATUS_LABELS = {
        'new': 'Nowy',
        'in_progress': 'W realizacji',
        'resolved': 'Rozwiązany',
        'rejected': 'Odrzucony'
    }

    # Relationships
    author = relationship('User', foreign_keys=[author_id], back_populates='forum_topics')
    status_changer = relationship('User', foreign_keys=[status_changed_by])
    replies = relationship('ForumReply', back_populates='topic', cascade='all, delete-orphan', order_by='ForumReply.created_at')
    attachments = relationship('ForumAttachment', back_populates='topic', cascade='all, delete-orphan',
                               primaryjoin="and_(ForumAttachment.topic_id==ForumTopic.id, ForumAttachment.attachment_type=='topic')")

    @property
    def reply_count(self):
        return len(self.replies)

    @property
    def last_activity(self):
        if self.replies:
            return max(r.created_at for r in self.replies)
        return self.created_at

    @property
    def category_label(self):
        return self.CATEGORY_LABELS.get(self.category, self.category)

    @property
    def status_label(self):
        return self.STATUS_LABELS.get(self.status, self.status)


class ForumReply(Base):
    """Forum replies to topics"""
    __tablename__ = 'forum_replies'

    id = Column(Integer, primary_key=True)
    topic_id = Column(Integer, ForeignKey('forum_topics.id'), nullable=False)
    author_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    content = Column(Text, nullable=False)
    is_ai_generated = Column(Boolean, default=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    topic = relationship('ForumTopic', back_populates='replies')
    author = relationship('User', back_populates='forum_replies')
    attachments = relationship('ForumAttachment', back_populates='reply', cascade='all, delete-orphan',
                               primaryjoin="and_(ForumAttachment.reply_id==ForumReply.id, ForumAttachment.attachment_type=='reply')")


class ForumAttachment(Base):
    """Forum file attachments for topics and replies"""
    __tablename__ = 'forum_attachments'

    id = Column(Integer, primary_key=True)

    # Polymorphic relationship (topic or reply)
    attachment_type = Column(String(20), nullable=False)  # 'topic' or 'reply'
    topic_id = Column(Integer, ForeignKey('forum_topics.id', ondelete='CASCADE'))
    reply_id = Column(Integer, ForeignKey('forum_replies.id', ondelete='CASCADE'))

    # File metadata
    original_filename = Column(String(255), nullable=False)
    stored_filename = Column(String(255), nullable=False, unique=True)
    file_extension = Column(String(10), nullable=False)
    file_size = Column(Integer, nullable=False)  # in bytes
    mime_type = Column(String(100), nullable=False)

    # Uploader
    uploaded_by = Column(Integer, ForeignKey('users.id'), nullable=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    topic = relationship('ForumTopic', back_populates='attachments', foreign_keys=[topic_id])
    reply = relationship('ForumReply', back_populates='attachments', foreign_keys=[reply_id])
    uploader = relationship('User')

    # Allowed file types
    ALLOWED_EXTENSIONS = {'jpg', 'jpeg', 'png', 'gif'}
    MAX_FILE_SIZE = 5 * 1024 * 1024  # 5MB

    @property
    def url(self):
        """Get the URL to serve this file"""
        date = self.created_at or datetime.now()
        subdir = 'topics' if self.attachment_type == 'topic' else 'replies'
        return f"/static/uploads/forum/{subdir}/{date.year}/{date.month:02d}/{self.stored_filename}"

    @property
    def is_image(self):
        """Check if this is an image file"""
        return self.mime_type.startswith('image/')

    @property
    def size_display(self):
        """Human-readable file size"""
        if self.file_size < 1024:
            return f"{self.file_size} B"
        elif self.file_size < 1024 * 1024:
            return f"{self.file_size / 1024:.1f} KB"
        else:
            return f"{self.file_size / (1024 * 1024):.1f} MB"


class AIAPICostLog(Base):
    """API cost tracking"""
    __tablename__ = 'ai_api_costs'

    id = Column(Integer, primary_key=True)
    timestamp = Column(DateTime, default=datetime.now, index=True)

    # API details
    api_provider = Column(String(50))  # 'gemini'
    model_name = Column(String(100))
    feature = Column(String(100))  # 'ai_chat', 'general', etc.

    # User context
    user_id = Column(Integer, ForeignKey('users.id'), index=True)

    # Token usage
    input_tokens = Column(Integer)
    output_tokens = Column(Integer)
    total_tokens = Column(Integer)

    # Costs
    input_cost = Column(Numeric(10, 6))
    output_cost = Column(Numeric(10, 6))
    total_cost = Column(Numeric(10, 6))

    # Status
    success = Column(Boolean, default=True)
    error_message = Column(Text)
    latency_ms = Column(Integer)

    # Privacy
    prompt_hash = Column(String(64))  # SHA256 hash, not storing actual prompts


# ============================================================
# CALENDAR / EVENTS
# ============================================================

class NordaEvent(Base):
    """Spotkania i wydarzenia Norda Biznes"""
    __tablename__ = 'norda_events'

    id = Column(Integer, primary_key=True)
    title = Column(String(255), nullable=False)
    description = Column(Text)
    event_type = Column(String(50), default='meeting')  # meeting, webinar, networking, other

    # Data i czas
    event_date = Column(Date, nullable=False)
    time_start = Column(Time)
    time_end = Column(Time)

    # Lokalizacja
    location = Column(String(500))  # Adres lub "Online"
    location_url = Column(String(1000))  # Link do Google Maps lub Zoom

    # Prelegent (opcjonalnie)
    speaker_name = Column(String(255))
    speaker_company_id = Column(Integer, ForeignKey('companies.id'))

    # Metadane
    is_featured = Column(Boolean, default=False)
    is_ai_generated = Column(Boolean, default=False)
    max_attendees = Column(Integer)
    created_by = Column(Integer, ForeignKey('users.id'))
    created_at = Column(DateTime, default=datetime.now)

    # Źródło danych (tracking)
    source = Column(String(255))  # np. 'kalendarz_norda_2026', 'manual', 'api'
    source_note = Column(Text)    # Pełna informacja o źródle

    # Relationships
    speaker_company = relationship('Company')
    creator = relationship('User', foreign_keys=[created_by])
    attendees = relationship('EventAttendee', back_populates='event', cascade='all, delete-orphan')

    @property
    def attendee_count(self):
        return len(self.attendees)

    @property
    def is_past(self):
        from datetime import date
        return self.event_date < date.today()


class EventAttendee(Base):
    """RSVP na wydarzenia"""
    __tablename__ = 'event_attendees'

    id = Column(Integer, primary_key=True)
    event_id = Column(Integer, ForeignKey('norda_events.id'), nullable=False)
    user_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    status = Column(String(20), default='confirmed')  # confirmed, maybe, declined
    registered_at = Column(DateTime, default=datetime.now)

    event = relationship('NordaEvent', back_populates='attendees')
    user = relationship('User')


# ============================================================
# PRIVATE MESSAGES
# ============================================================

class PrivateMessage(Base):
    """Wiadomości prywatne między członkami"""
    __tablename__ = 'private_messages'

    id = Column(Integer, primary_key=True)
    sender_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    recipient_id = Column(Integer, ForeignKey('users.id'), nullable=False)

    subject = Column(String(255))
    content = Column(Text, nullable=False)

    is_read = Column(Boolean, default=False)
    read_at = Column(DateTime)

    # Dla wątków konwersacji
    parent_id = Column(Integer, ForeignKey('private_messages.id'))

    created_at = Column(DateTime, default=datetime.now)

    sender = relationship('User', foreign_keys=[sender_id], backref='sent_messages')
    recipient = relationship('User', foreign_keys=[recipient_id], backref='received_messages')
    parent = relationship('PrivateMessage', remote_side=[id])


# ============================================================
# B2B CLASSIFIEDS
# ============================================================

class Classified(Base):
    """Ogłoszenia B2B - Szukam/Oferuję"""
    __tablename__ = 'classifieds'

    id = Column(Integer, primary_key=True)
    author_id = Column(Integer, ForeignKey('users.id'), nullable=False)
    company_id = Column(Integer, ForeignKey('companies.id'))

    # Typ ogłoszenia
    listing_type = Column(String(20), nullable=False)  # 'szukam', 'oferuje'
    category = Column(String(50), nullable=False)  # uslugi, produkty, wspolpraca, praca, inne

    title = Column(String(255), nullable=False)
    description = Column(Text, nullable=False)

    # Opcjonalne szczegóły
    budget_info = Column(String(255))  # "do negocjacji", "5000-10000 PLN"
    location_info = Column(String(255))  # Wejherowo, Cała Polska, Online

    # Status
    is_active = Column(Boolean, default=True)
    is_ai_generated = Column(Boolean, default=False)
    is_test = Column(Boolean, default=False)  # Oznaczenie dla testowych ogłoszeń
    expires_at = Column(DateTime)  # Auto-wygaśnięcie po 30 dniach
    views_count = Column(Integer, default=0)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    author = relationship('User', backref='classifieds')
    company = relationship('Company')

    @property
    def is_expired(self):
        if self.expires_at:
            return datetime.now() > self.expires_at
        return False


class CompanyContact(Base):
    """Multiple contacts (phones, emails) per company with source tracking"""
    __tablename__ = 'company_contacts'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)

    # Contact type: 'phone', 'email', 'fax', 'mobile'
    contact_type = Column(String(20), nullable=False, index=True)

    # Contact value (phone number or email address)
    value = Column(String(255), nullable=False)

    # Purpose/description: 'Biuro', 'Sprzedaż', 'Właściciel', 'Transport', 'Serwis', etc.
    purpose = Column(String(100))

    # Is this the primary contact of this type?
    is_primary = Column(Boolean, default=False)

    # Source of this contact data
    source = Column(String(100))  # 'website', 'krs', 'google_business', 'facebook', 'manual', 'brave_search'
    source_url = Column(String(500))  # URL where the contact was found
    source_date = Column(Date)  # When the contact was found/verified

    # Validation
    is_verified = Column(Boolean, default=False)
    verified_at = Column(DateTime)
    verified_by = Column(String(100))

    # Metadata
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationship
    company = relationship('Company', backref='contacts')

    __table_args__ = (
        UniqueConstraint('company_id', 'contact_type', 'value', name='uq_company_contact_type_value'),
    )


class CompanySocialMedia(Base):
    """Social media profiles for companies with verification tracking"""
    __tablename__ = 'company_social_media'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)
    platform = Column(String(50), nullable=False, index=True)  # facebook, linkedin, instagram, youtube, twitter
    url = Column(String(500), nullable=False)

    # Tracking freshness
    verified_at = Column(DateTime, nullable=False, default=datetime.now, index=True)
    source = Column(String(100))  # website_scrape, brave_search, manual, facebook_api

    # Validation
    is_valid = Column(Boolean, default=True)
    last_checked_at = Column(DateTime)
    check_status = Column(String(50))  # ok, 404, redirect, blocked

    # Metadata from platform
    page_name = Column(String(255))
    followers_count = Column(Integer)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationship
    company = relationship('Company', backref='social_media_profiles')

    __table_args__ = (
        UniqueConstraint('company_id', 'platform', 'url', name='uq_company_platform_url'),
    )


class CompanyRecommendation(Base):
    """Peer recommendations between NORDA BIZNES members"""
    __tablename__ = 'company_recommendations'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False, index=True)

    # Recommendation content
    recommendation_text = Column(Text, nullable=False)
    service_category = Column(String(200))  # Optional: specific service recommended for

    # Privacy settings
    show_contact = Column(Boolean, default=True)  # Show recommender's contact info

    # Moderation
    status = Column(String(20), default='pending', index=True)  # pending, approved, rejected
    moderated_by = Column(Integer, ForeignKey('users.id'), nullable=True)
    moderated_at = Column(DateTime)
    rejection_reason = Column(Text)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', backref='recommendations')
    user = relationship('User', foreign_keys=[user_id], backref='recommendations_given')
    moderator = relationship('User', foreign_keys=[moderated_by], backref='recommendations_moderated')

    __table_args__ = (
        UniqueConstraint('user_id', 'company_id', name='uq_user_company_recommendation'),
    )


class UserNotification(Base):
    """
    In-app notifications for users.
    Supports badges and notification center.
    """
    __tablename__ = 'user_notifications'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False, index=True)

    # Notification content
    title = Column(String(255), nullable=False)
    message = Column(Text)
    notification_type = Column(String(50), default='info', index=True)
    # Types: news, system, message, event, alert

    # Related entity (optional)
    related_type = Column(String(50))  # company_news, event, message
    related_id = Column(Integer)

    # Status
    is_read = Column(Boolean, default=False, index=True)
    read_at = Column(DateTime)

    # Link
    action_url = Column(String(500))

    # Timestamps
    created_at = Column(DateTime, default=datetime.now, index=True)

    # Relationship
    user = relationship('User', backref='notifications')

    def mark_as_read(self):
        self.is_read = True
        self.read_at = datetime.now()


# ============================================================
# GOOGLE BUSINESS PROFILE AUDIT
# ============================================================

class GBPAudit(Base):
    """
    Google Business Profile audit results for companies.
    Tracks completeness scores and provides improvement recommendations.
    """
    __tablename__ = 'gbp_audits'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)

    # Audit timestamp
    audit_date = Column(DateTime, default=datetime.now, nullable=False, index=True)

    # Completeness scoring (0-100)
    completeness_score = Column(Integer)

    # Field-by-field status tracking
    # Example: {"name": {"status": "complete", "value": "Company Name"}, "phone": {"status": "missing"}, ...}
    fields_status = Column(JSONB)

    # AI-generated recommendations
    # Example: [{"priority": "high", "field": "description", "recommendation": "Add a detailed business description..."}, ...]
    recommendations = Column(JSONB)

    # Individual field scores (for detailed breakdown)
    has_name = Column(Boolean, default=False)
    has_address = Column(Boolean, default=False)
    has_phone = Column(Boolean, default=False)
    has_website = Column(Boolean, default=False)
    has_hours = Column(Boolean, default=False)
    has_categories = Column(Boolean, default=False)
    has_photos = Column(Boolean, default=False)
    has_description = Column(Boolean, default=False)
    has_services = Column(Boolean, default=False)
    has_reviews = Column(Boolean, default=False)

    # Photo counts
    photo_count = Column(Integer, default=0)
    logo_present = Column(Boolean, default=False)
    cover_photo_present = Column(Boolean, default=False)

    # Review metrics
    review_count = Column(Integer, default=0)
    average_rating = Column(Numeric(2, 1))

    # Google Place data
    google_place_id = Column(String(100))
    google_maps_url = Column(String(500))

    # Audit metadata
    audit_source = Column(String(50), default='manual')  # manual, automated, api
    audit_version = Column(String(20), default='1.0')
    audit_errors = Column(Text)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationship
    company = relationship('Company', backref='gbp_audits')

    def __repr__(self):
        return f'<GBPAudit company_id={self.company_id} score={self.completeness_score}>'

    @property
    def score_category(self):
        """Return score category: excellent, good, needs_work, poor"""
        if self.completeness_score is None:
            return 'unknown'
        if self.completeness_score >= 90:
            return 'excellent'
        elif self.completeness_score >= 70:
            return 'good'
        elif self.completeness_score >= 50:
            return 'needs_work'
        else:
            return 'poor'


# ============================================================
# IT INFRASTRUCTURE AUDIT
# ============================================================

class ITAudit(Base):
    """
    IT infrastructure audit for companies.
    Tracks IT infrastructure, security posture, and collaboration readiness.
    Used for cross-company collaboration matching.
    """
    __tablename__ = 'it_audits'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'),
                       nullable=False, index=True)

    # Audit timestamp and metadata
    audit_date = Column(DateTime, default=datetime.now, nullable=False, index=True)
    audit_source = Column(String(50), default='form')  # form, api_sync
    audited_by = Column(Integer, ForeignKey('users.id'))

    # === SCORES (0-100) ===
    overall_score = Column(Integer)
    completeness_score = Column(Integer)
    security_score = Column(Integer)
    collaboration_score = Column(Integer)
    maturity_level = Column(String(20))  # basic, developing, established, advanced

    # === SECTION 1: IT CONTACT ===
    has_it_manager = Column(Boolean, default=False)
    it_outsourced = Column(Boolean, default=False)
    it_provider_name = Column(String(255))
    it_contact_name = Column(String(255))
    it_contact_email = Column(String(255))

    # === SECTION 2: CLOUD & IDENTITY ===
    has_azure_ad = Column(Boolean, default=False)
    azure_tenant_name = Column(String(255))
    azure_user_count = Column(String(20))  # Range: 1-10, 11-50, 51-100, 100+
    has_m365 = Column(Boolean, default=False)
    m365_plans = Column(ARRAY(String))  # Business Basic, Business Standard, E3, E5, etc.
    teams_usage = Column(ARRAY(String))  # chat, meetings, files, phone
    has_google_workspace = Column(Boolean, default=False)

    # === SECTION 3: SERVER INFRASTRUCTURE ===
    server_count = Column(String(20))  # Range: 0, 1-3, 4-10, 10+
    server_types = Column(ARRAY(String))  # physical, vm_onprem, cloud_iaas
    virtualization_platform = Column(String(50))  # none, vmware, hyperv, proxmox, kvm
    server_os = Column(ARRAY(String))  # windows_server, linux_ubuntu, linux_debian, linux_rhel
    network_firewall_brand = Column(String(100))

    # === SECTION 4: ENDPOINTS ===
    employee_count = Column(String(20))  # Range: 1-10, 11-50, 51-100, 100+
    computer_count = Column(String(20))  # Range: 1-10, 11-50, 51-100, 100+
    desktop_os = Column(ARRAY(String))  # windows_10, windows_11, macos, linux
    has_mdm = Column(Boolean, default=False)
    mdm_solution = Column(String(50))  # intune, jamf, other

    # === SECTION 5: SECURITY ===
    antivirus_solution = Column(String(50))  # none, windows_defender, eset, kaspersky, other
    has_edr = Column(Boolean, default=False)
    edr_solution = Column(String(100))  # microsoft_defender_atp, crowdstrike, sentinelone, other
    has_vpn = Column(Boolean, default=False)
    vpn_solution = Column(String(50))  # ipsec, wireguard, openvpn, fortinet, other
    has_mfa = Column(Boolean, default=False)
    mfa_scope = Column(ARRAY(String))  # email, vpn, erp, all_apps

    # === SECTION 6: BACKUP & DISASTER RECOVERY ===
    backup_solution = Column(String(50))  # none, veeam, acronis, pbs, azure_backup, other
    backup_targets = Column(ARRAY(String))  # local_nas, offsite, cloud, tape
    backup_frequency = Column(String(20))  # daily, weekly, monthly, continuous
    has_proxmox_pbs = Column(Boolean, default=False)
    has_dr_plan = Column(Boolean, default=False)

    # === SECTION 7: MONITORING ===
    monitoring_solution = Column(String(50))  # none, zabbix, prtg, nagios, datadog, other
    zabbix_integration = Column(JSONB)  # {hostname: '', agent_installed: bool, templates: []}

    # === SECTION 8: BUSINESS APPS ===
    ticketing_system = Column(String(50))  # none, freshdesk, zendesk, jira_service, other
    erp_system = Column(String(50))  # none, sap, microsoft_dynamics, enova, optima, other
    crm_system = Column(String(50))  # none, salesforce, hubspot, pipedrive, other
    document_management = Column(String(50))  # none, sharepoint, google_drive, dropbox, other

    # === SECTION 9: ACTIVE DIRECTORY ===
    has_local_ad = Column(Boolean, default=False)
    ad_domain_name = Column(String(255))
    has_ad_azure_sync = Column(Boolean, default=False)  # Azure AD Connect / Cloud Sync

    # === COLLABORATION FLAGS (for matching algorithm) ===
    open_to_shared_licensing = Column(Boolean, default=False)
    open_to_backup_replication = Column(Boolean, default=False)
    open_to_teams_federation = Column(Boolean, default=False)
    open_to_shared_monitoring = Column(Boolean, default=False)
    open_to_collective_purchasing = Column(Boolean, default=False)
    open_to_knowledge_sharing = Column(Boolean, default=False)

    # === RAW DATA & METADATA ===
    form_data = Column(JSONB)  # Full form submission for reference
    recommendations = Column(JSONB)  # AI-generated recommendations
    audit_errors = Column(Text)  # Any errors during audit processing

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', backref='it_audits')
    auditor = relationship('User', foreign_keys=[audited_by])

    def __repr__(self):
        return f'<ITAudit company_id={self.company_id} score={self.overall_score}>'

    @property
    def maturity_label(self):
        """Return Polish label for maturity level"""
        labels = {
            'basic': 'Podstawowy',
            'developing': 'Rozwijający się',
            'established': 'Ugruntowany',
            'advanced': 'Zaawansowany'
        }
        return labels.get(self.maturity_level, 'Nieznany')

    @property
    def score_category(self):
        """Return score category: excellent, good, needs_work, poor"""
        if self.overall_score is None:
            return 'unknown'
        if self.overall_score >= 80:
            return 'excellent'
        elif self.overall_score >= 60:
            return 'good'
        elif self.overall_score >= 40:
            return 'needs_work'
        else:
            return 'poor'

    @property
    def collaboration_flags_count(self):
        """Count how many collaboration flags are enabled"""
        flags = [
            self.open_to_shared_licensing,
            self.open_to_backup_replication,
            self.open_to_teams_federation,
            self.open_to_shared_monitoring,
            self.open_to_collective_purchasing,
            self.open_to_knowledge_sharing
        ]
        return sum(1 for f in flags if f)


class ITCollaborationMatch(Base):
    """
    IT collaboration matches between companies.
    Stores potential collaboration opportunities discovered by the matching algorithm.
    Match types: shared_licensing, backup_replication, teams_federation,
                 shared_monitoring, collective_purchasing, knowledge_sharing
    """
    __tablename__ = 'it_collaboration_matches'

    id = Column(Integer, primary_key=True)
    company_a_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'),
                         nullable=False, index=True)
    company_b_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'),
                         nullable=False, index=True)

    # Match details
    match_type = Column(String(50), nullable=False, index=True)
    # Types: shared_licensing, backup_replication, teams_federation,
    #        shared_monitoring, collective_purchasing, knowledge_sharing
    match_reason = Column(Text)  # Human-readable explanation of why this is a match
    match_score = Column(Integer)  # 0-100 strength of the match

    # Status: suggested, contacted, in_progress, completed, declined
    status = Column(String(20), default='suggested', index=True)

    # Shared attributes that led to this match (JSONB for flexibility)
    # Example: {"m365_plans": ["E3", "E5"], "has_proxmox_pbs": true}
    shared_attributes = Column(JSONB)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now, index=True)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company_a = relationship('Company', foreign_keys=[company_a_id],
                            backref='collaboration_matches_as_a')
    company_b = relationship('Company', foreign_keys=[company_b_id],
                            backref='collaboration_matches_as_b')

    __table_args__ = (
        UniqueConstraint('company_a_id', 'company_b_id', 'match_type',
                        name='uq_it_collab_match_pair_type'),
    )

    def __repr__(self):
        return f'<ITCollaborationMatch {self.company_a_id}<->{self.company_b_id} type={self.match_type}>'

    @property
    def match_type_label(self):
        """Return Polish label for match type"""
        labels = {
            'shared_licensing': 'Współdzielone licencje',
            'backup_replication': 'Replikacja backupów',
            'teams_federation': 'Federacja Teams',
            'shared_monitoring': 'Wspólny monitoring',
            'collective_purchasing': 'Zakupy grupowe',
            'knowledge_sharing': 'Wymiana wiedzy'
        }
        return labels.get(self.match_type, self.match_type)

    @property
    def status_label(self):
        """Return Polish label for status"""
        labels = {
            'suggested': 'Sugerowane',
            'contacted': 'Skontaktowano',
            'in_progress': 'W trakcie',
            'completed': 'Zakończone',
            'declined': 'Odrzucone'
        }
        return labels.get(self.status, self.status)


# ============================================================
# MEMBERSHIP FEES
# ============================================================

class MembershipFee(Base):
    """
    Membership fee records for companies.
    Tracks monthly payments from Norda Biznes members.
    """
    __tablename__ = 'membership_fees'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)

    # Period identification
    fee_year = Column(Integer, nullable=False)  # e.g., 2026
    fee_month = Column(Integer, nullable=False)  # 1-12

    # Fee details
    amount = Column(Numeric(10, 2), nullable=False)  # Amount due in PLN
    amount_paid = Column(Numeric(10, 2), default=0)  # Amount actually paid

    # Payment status: pending, paid, partial, overdue, waived
    status = Column(String(20), default='pending', index=True)

    # Payment tracking
    payment_date = Column(Date)
    payment_method = Column(String(50))  # transfer, cash, card, other
    payment_reference = Column(String(100))  # Bank transfer reference

    # Admin tracking
    recorded_by = Column(Integer, ForeignKey('users.id'))
    recorded_at = Column(DateTime)

    notes = Column(Text)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', backref='membership_fees')
    recorded_by_user = relationship('User', foreign_keys=[recorded_by])

    __table_args__ = (
        UniqueConstraint('company_id', 'fee_year', 'fee_month', name='uq_company_fee_period'),
    )

    @property
    def is_fully_paid(self):
        return (self.amount_paid or 0) >= self.amount

    @property
    def outstanding_amount(self):
        return max(0, float(self.amount) - float(self.amount_paid or 0))


class MembershipFeeConfig(Base):
    """
    Configuration for membership fees.
    Allows variable amounts per company or category.
    """
    __tablename__ = 'membership_fee_config'

    id = Column(Integer, primary_key=True)

    # Scope: global, category, or company
    scope = Column(String(20), nullable=False)  # 'global', 'category', 'company'
    category_id = Column(Integer, ForeignKey('categories.id'), nullable=True)
    company_id = Column(Integer, ForeignKey('companies.id'), nullable=True)

    monthly_amount = Column(Numeric(10, 2), nullable=False)

    valid_from = Column(Date, nullable=False)
    valid_until = Column(Date)  # NULL = currently active

    created_by = Column(Integer, ForeignKey('users.id'))
    created_at = Column(DateTime, default=datetime.now)
    notes = Column(Text)

    # Relationships
    category = relationship('Category')
    company = relationship('Company')


# ============================================================
# ZIELONY OKRĘG PRZEMYSŁOWY KASZUBIA (ZOPK)
# ============================================================

class ZOPKProject(Base):
    """
    Sub-projects within ZOPK initiative.
    Examples: offshore wind, nuclear plant, data centers, hydrogen labs
    """
    __tablename__ = 'zopk_projects'

    id = Column(Integer, primary_key=True)
    slug = Column(String(100), unique=True, nullable=False, index=True)
    name = Column(String(255), nullable=False)
    description = Column(Text)

    # Project details
    project_type = Column(String(50))  # energy, infrastructure, technology, defense
    status = Column(String(50), default='planned')  # planned, in_progress, completed
    start_date = Column(Date)
    end_date = Column(Date)

    # Location info
    location = Column(String(255))
    region = Column(String(100))  # Wejherowo, Rumia, Gdynia, etc.

    # Key metrics
    estimated_investment = Column(Numeric(15, 2))  # Investment amount in PLN
    estimated_jobs = Column(Integer)  # Number of jobs created

    # Visual
    icon = Column(String(50))  # CSS icon class or emoji
    color = Column(String(20))  # HEX color for badges

    # Display order
    sort_order = Column(Integer, default=0)
    is_featured = Column(Boolean, default=False)
    is_active = Column(Boolean, default=True)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)


class ZOPKStakeholder(Base):
    """
    Key people and organizations involved in ZOPK.
    Politicians, coordinators, companies, institutions.
    """
    __tablename__ = 'zopk_stakeholders'

    id = Column(Integer, primary_key=True)

    # Person or organization
    stakeholder_type = Column(String(20), nullable=False)  # person, organization
    name = Column(String(255), nullable=False)

    # Role and affiliation
    role = Column(String(255))  # Koordynator, Minister, Starosta, etc.
    organization = Column(String(255))  # MON, Starostwo Wejherowskie, etc.

    # Contact (optional, public info only)
    email = Column(String(255))
    phone = Column(String(50))
    website = Column(String(500))

    # Social media
    linkedin_url = Column(String(500))
    twitter_url = Column(String(500))

    # Photo/logo
    photo_url = Column(String(500))

    # Description
    bio = Column(Text)

    # Categorization
    category = Column(String(50))  # government, local_authority, business, academic
    importance = Column(Integer, default=0)  # For sorting (higher = more important)

    is_active = Column(Boolean, default=True)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    project_links = relationship('ZOPKStakeholderProject', back_populates='stakeholder')

    __table_args__ = (
        UniqueConstraint('name', name='uq_zopk_stakeholder_name'),
    )


class ZOPKStakeholderProject(Base):
    """Link table between stakeholders and projects"""
    __tablename__ = 'zopk_stakeholder_projects'

    id = Column(Integer, primary_key=True)
    stakeholder_id = Column(Integer, ForeignKey('zopk_stakeholders.id', ondelete='CASCADE'), nullable=False)
    project_id = Column(Integer, ForeignKey('zopk_projects.id', ondelete='CASCADE'), nullable=False)
    role_in_project = Column(String(255))  # e.g., "Koordynator", "Inwestor"

    created_at = Column(DateTime, default=datetime.now)

    stakeholder = relationship('ZOPKStakeholder', back_populates='project_links')
    project = relationship('ZOPKProject', backref='stakeholder_links')

    __table_args__ = (
        UniqueConstraint('stakeholder_id', 'project_id', name='uq_stakeholder_project'),
    )


class ZOPKNews(Base):
    """
    News articles about ZOPK with approval workflow.
    Can be fetched automatically or added manually.
    """
    __tablename__ = 'zopk_news'

    id = Column(Integer, primary_key=True)

    # Source information
    title = Column(String(500), nullable=False)
    description = Column(Text)
    url = Column(String(1000), nullable=False)
    source_name = Column(String(200))  # Portal name: trojmiasto.pl, etc.
    source_domain = Column(String(200))  # Domain: trojmiasto.pl

    # Article details
    published_at = Column(DateTime)
    author = Column(String(255))
    image_url = Column(String(1000))

    # Categorization
    news_type = Column(String(50))  # news, announcement, interview, press_release
    project_id = Column(Integer, ForeignKey('zopk_projects.id'))  # Link to sub-project

    # AI Analysis
    relevance_score = Column(Numeric(3, 2))  # 0.00-1.00
    sentiment = Column(String(20))  # positive, neutral, negative
    ai_summary = Column(Text)  # AI-generated summary
    keywords = Column(StringArray)  # Extracted keywords

    # Cross-verification (multi-source confidence)
    confidence_score = Column(Integer, default=1)  # 1-5, increases with source confirmations
    source_count = Column(Integer, default=1)  # Number of sources that found this story
    sources_list = Column(StringArray)  # List of sources: ['brave', 'google_news', 'rss_trojmiasto']
    title_hash = Column(String(64), index=True)  # For fuzzy title matching (normalized)
    is_auto_verified = Column(Boolean, default=False)  # True if 3+ sources confirmed

    # AI Relevance Evaluation (Gemini)
    ai_relevant = Column(Boolean)  # True = relevant to ZOPK, False = not relevant, NULL = not evaluated
    ai_relevance_score = Column(Integer)  # 1-5 stars: 1=weak match, 5=perfect match
    ai_evaluation_reason = Column(Text)  # AI's explanation of relevance decision
    ai_evaluated_at = Column(DateTime)  # When AI evaluation was performed
    ai_model = Column(String(100))  # Which AI model was used (e.g., gemini-3-flash-preview)

    # Moderation workflow
    status = Column(String(20), default='pending', index=True)  # pending, approved, rejected, auto_approved
    moderated_by = Column(Integer, ForeignKey('users.id'))
    moderated_at = Column(DateTime)
    rejection_reason = Column(Text)

    # Source tracking
    source_type = Column(String(50), default='manual')  # manual, brave_search, rss, scraper
    fetch_job_id = Column(String(100))  # ID of the fetch job that found this

    # Deduplication
    url_hash = Column(String(64), unique=True, index=True)  # SHA256 of URL

    is_featured = Column(Boolean, default=False)
    views_count = Column(Integer, default=0)

    # Full content (scraped from source URL) - for knowledge extraction
    full_content = Column(Text)  # Full article text (without HTML, ads, navigation)
    content_scraped_at = Column(DateTime)  # When content was scraped
    scrape_status = Column(String(20), default='pending', index=True)  # pending, scraped, failed, skipped
    scrape_error = Column(Text)  # Error message if scraping failed
    scrape_attempts = Column(Integer, default=0)  # Number of scraping attempts
    content_word_count = Column(Integer)  # Word count of scraped content
    content_language = Column(String(10), default='pl')  # pl, en

    # Knowledge extraction status
    knowledge_extracted = Column(Boolean, default=False, index=True)  # True if chunks/facts/entities extracted
    knowledge_extracted_at = Column(DateTime)  # When knowledge was extracted

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    project = relationship('ZOPKProject', backref='news_items')
    moderator = relationship('User', foreign_keys=[moderated_by])


class ZOPKResource(Base):
    """
    Resources: documents, links, images, videos related to ZOPK.
    Knowledge base materials.
    """
    __tablename__ = 'zopk_resources'

    id = Column(Integer, primary_key=True)

    # Resource identification
    title = Column(String(255), nullable=False)
    description = Column(Text)

    # Resource type
    resource_type = Column(String(50), nullable=False)  # link, document, image, video, map

    # URL or file path
    url = Column(String(1000))
    file_path = Column(String(500))  # For uploaded files
    file_size = Column(Integer)
    mime_type = Column(String(100))

    # Thumbnail
    thumbnail_url = Column(String(1000))

    # Categorization
    category = Column(String(50))  # official, media, research, presentation
    project_id = Column(Integer, ForeignKey('zopk_projects.id'))

    # Tags for search
    tags = Column(StringArray)

    # Source
    source_name = Column(String(255))
    source_date = Column(Date)

    # Moderation
    status = Column(String(20), default='approved', index=True)  # pending, approved, rejected
    uploaded_by = Column(Integer, ForeignKey('users.id'))

    is_featured = Column(Boolean, default=False)
    sort_order = Column(Integer, default=0)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    project = relationship('ZOPKProject', backref='resources')
    uploader = relationship('User', foreign_keys=[uploaded_by])


class ZOPKCompanyLink(Base):
    """
    Links between ZOPK projects and Norda Biznes member companies.
    Shows which local companies can benefit or collaborate.
    """
    __tablename__ = 'zopk_company_links'

    id = Column(Integer, primary_key=True)

    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False)
    project_id = Column(Integer, ForeignKey('zopk_projects.id', ondelete='CASCADE'), nullable=False)

    # Type of involvement
    link_type = Column(String(50), nullable=False)  # potential_supplier, partner, investor, beneficiary

    # Description of potential collaboration
    collaboration_description = Column(Text)

    # Relevance scoring
    relevance_score = Column(Integer)  # 1-100

    # Status
    status = Column(String(20), default='suggested')  # suggested, confirmed, active, completed

    # Admin notes
    admin_notes = Column(Text)
    created_by = Column(Integer, ForeignKey('users.id'))

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', backref='zopk_project_links')
    project = relationship('ZOPKProject', backref='company_links')
    creator = relationship('User', foreign_keys=[created_by])

    __table_args__ = (
        UniqueConstraint('company_id', 'project_id', 'link_type', name='uq_company_project_link'),
    )


class ZOPKNewsFetchJob(Base):
    """
    Tracking for automated news fetch jobs.
    Records when and what was searched.
    """
    __tablename__ = 'zopk_news_fetch_jobs'

    id = Column(Integer, primary_key=True)
    job_id = Column(String(100), unique=True, nullable=False, index=True)

    # Job configuration
    search_query = Column(String(500))
    search_api = Column(String(50))  # brave, google, bing
    date_range_start = Column(Date)
    date_range_end = Column(Date)

    # Results
    results_found = Column(Integer, default=0)
    results_new = Column(Integer, default=0)  # New (not duplicates)
    results_approved = Column(Integer, default=0)

    # Status
    status = Column(String(20), default='pending')  # pending, running, completed, failed
    error_message = Column(Text)

    # Timing
    started_at = Column(DateTime)
    completed_at = Column(DateTime)

    # Trigger
    triggered_by = Column(String(50))  # cron, manual, admin
    triggered_by_user = Column(Integer, ForeignKey('users.id'))

    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    user = relationship('User', foreign_keys=[triggered_by_user])


# ============================================================
# ZOPK KNOWLEDGE BASE (AI-powered, with pgvector)
# ============================================================

class ZOPKKnowledgeChunk(Base):
    """
    Knowledge chunks extracted from approved ZOPK news articles.
    Each chunk is a semantically coherent piece of text with embedding vector
    for similarity search (RAG - Retrieval Augmented Generation).

    Best practices:
    - Chunk size: 500-1000 tokens with ~100 token overlap
    - Embedding model: text-embedding-004 (768 dimensions)
    """
    __tablename__ = 'zopk_knowledge_chunks'

    id = Column(Integer, primary_key=True)

    # Source tracking
    source_news_id = Column(Integer, ForeignKey('zopk_news.id'), nullable=False, index=True)

    # Chunk content
    content = Column(Text, nullable=False)  # The actual text chunk
    content_clean = Column(Text)  # Cleaned/normalized version for processing
    chunk_index = Column(Integer)  # Position in the original article (0, 1, 2...)
    token_count = Column(Integer)  # Approximate token count

    # Semantic embedding (pgvector)
    # Using 768 dimensions for Google text-embedding-004
    # Will be stored as: embedding vector(768)
    embedding = Column(Text)  # Stored as JSON string, converted to vector for queries

    # AI-extracted metadata
    chunk_type = Column(String(50))  # narrative, fact, quote, statistic, event, definition
    summary = Column(Text)  # 1-2 sentence summary
    keywords = Column(PG_ARRAY(String(100)) if not IS_SQLITE else Text)  # Extracted keywords
    language = Column(String(10), default='pl')  # pl, en

    # Context information
    context_date = Column(Date)  # Date the information refers to (not article date)
    context_location = Column(String(255))  # Geographic location if mentioned

    # Quality & relevance
    importance_score = Column(Integer)  # 1-5, how important this information is
    confidence_score = Column(Numeric(3, 2))  # 0.00-1.00, AI confidence in extraction

    # Moderation
    is_verified = Column(Boolean, default=False)  # Human verified
    verified_by = Column(Integer, ForeignKey('users.id'))
    verified_at = Column(DateTime)

    # Processing metadata
    extraction_model = Column(String(100))  # gemini-3-flash-preview, gpt-4, etc.
    extracted_at = Column(DateTime, default=datetime.now)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    source_news = relationship('ZOPKNews', backref='knowledge_chunks')
    verifier = relationship('User', foreign_keys=[verified_by])


class ZOPKKnowledgeEntity(Base):
    """
    Named entities extracted from ZOPK knowledge base.
    Entities are deduplicated and enriched across all sources.

    Types: company, person, place, organization, project, technology
    """
    __tablename__ = 'zopk_knowledge_entities'

    id = Column(Integer, primary_key=True)

    # Entity identification
    entity_type = Column(String(50), nullable=False, index=True)
    name = Column(String(255), nullable=False)
    normalized_name = Column(String(255), index=True)  # Lowercase, no special chars (for dedup)
    aliases = Column(PG_ARRAY(String(255)) if not IS_SQLITE else Text)  # Alternative names

    # Description
    description = Column(Text)  # AI-generated description
    short_description = Column(String(500))  # One-liner

    # Linking to existing data
    company_id = Column(Integer, ForeignKey('companies.id'))  # Link to Norda company if exists
    zopk_project_id = Column(Integer, ForeignKey('zopk_projects.id'))  # Link to ZOPK project
    external_url = Column(String(1000))  # Wikipedia, company website, etc.

    # Entity metadata (JSONB for flexibility)
    # Note: 'metadata' is reserved in SQLAlchemy, using 'entity_metadata'
    entity_metadata = Column(PG_JSONB if not IS_SQLITE else Text)  # {role: "CEO", founded: 2020, ...}

    # Statistics
    mentions_count = Column(Integer, default=0)
    first_mentioned_at = Column(DateTime)
    last_mentioned_at = Column(DateTime)

    # Embedding for entity similarity
    embedding = Column(Text)  # Entity description embedding

    # Quality
    is_verified = Column(Boolean, default=False)
    merged_into_id = Column(Integer, ForeignKey('zopk_knowledge_entities.id'))  # For deduplication

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', foreign_keys=[company_id])
    zopk_project = relationship('ZOPKProject', foreign_keys=[zopk_project_id])
    merged_into = relationship('ZOPKKnowledgeEntity', remote_side=[id], foreign_keys=[merged_into_id])


class ZOPKKnowledgeFact(Base):
    """
    Structured facts extracted from knowledge chunks.
    Facts are atomic, verifiable pieces of information.

    Examples:
    - "ZOPK otrzymał 500 mln PLN dofinansowania w 2024"
    - "Port Gdynia jest głównym partnerem projektu"
    - "Projekt zakłada utworzenie 5000 miejsc pracy"
    """
    __tablename__ = 'zopk_knowledge_facts'

    id = Column(Integer, primary_key=True)

    # Source
    source_chunk_id = Column(Integer, ForeignKey('zopk_knowledge_chunks.id'), nullable=False, index=True)
    source_news_id = Column(Integer, ForeignKey('zopk_news.id'), index=True)

    # Fact content
    fact_type = Column(String(50), nullable=False)  # statistic, event, statement, decision, milestone
    subject = Column(String(255))  # Who/what the fact is about
    predicate = Column(String(100))  # Action/relation type
    object = Column(Text)  # The actual information
    full_text = Column(Text, nullable=False)  # Complete fact as sentence

    # Structured data (for queryable facts)
    numeric_value = Column(Numeric(20, 2))  # If fact contains number
    numeric_unit = Column(String(50))  # PLN, EUR, jobs, MW, etc.
    date_value = Column(Date)  # If fact refers to specific date

    # Context
    context = Column(Text)  # Surrounding context for disambiguation
    citation = Column(Text)  # Original quote if applicable

    # Entities involved (denormalized for quick access)
    entities_involved = Column(PG_JSONB if not IS_SQLITE else Text)  # [{id: 1, name: "...", type: "company"}, ...]

    # Quality & verification
    confidence_score = Column(Numeric(3, 2))  # AI confidence
    is_verified = Column(Boolean, default=False)
    contradicts_fact_id = Column(Integer, ForeignKey('zopk_knowledge_facts.id'))  # If contradicted

    # Embedding for fact similarity
    embedding = Column(Text)

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    source_chunk = relationship('ZOPKKnowledgeChunk', backref='facts')
    source_news = relationship('ZOPKNews', backref='facts')
    contradicted_by = relationship('ZOPKKnowledgeFact', remote_side=[id], foreign_keys=[contradicts_fact_id])


class ZOPKKnowledgeEntityMention(Base):
    """
    Links between knowledge chunks and entities.
    Tracks where each entity is mentioned and in what context.
    """
    __tablename__ = 'zopk_knowledge_entity_mentions'

    id = Column(Integer, primary_key=True)

    chunk_id = Column(Integer, ForeignKey('zopk_knowledge_chunks.id'), nullable=False, index=True)
    entity_id = Column(Integer, ForeignKey('zopk_knowledge_entities.id'), nullable=False, index=True)

    # Mention details
    mention_text = Column(String(500))  # Exact text that matched the entity
    mention_type = Column(String(50))  # direct, reference, pronoun
    start_position = Column(Integer)  # Character position in chunk
    end_position = Column(Integer)

    # Context
    sentiment = Column(String(20))  # positive, neutral, negative
    role_in_context = Column(String(100))  # subject, object, beneficiary, partner

    confidence = Column(Numeric(3, 2))  # Entity linking confidence

    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    chunk = relationship('ZOPKKnowledgeChunk', backref='entity_mentions')
    entity = relationship('ZOPKKnowledgeEntity', backref='mentions')

    __table_args__ = (
        UniqueConstraint('chunk_id', 'entity_id', 'start_position', name='uq_chunk_entity_position'),
    )


class ZOPKKnowledgeRelation(Base):
    """
    Relationships between entities discovered in the knowledge base.
    Forms a knowledge graph of ZOPK ecosystem.

    Examples:
    - Company A → "partner" → Company B
    - Person X → "CEO of" → Company Y
    - Project Z → "funded by" → Organization W
    """
    __tablename__ = 'zopk_knowledge_relations'

    id = Column(Integer, primary_key=True)

    # Entities involved
    entity_a_id = Column(Integer, ForeignKey('zopk_knowledge_entities.id'), nullable=False, index=True)
    entity_b_id = Column(Integer, ForeignKey('zopk_knowledge_entities.id'), nullable=False, index=True)

    # Relation definition
    relation_type = Column(String(100), nullable=False)  # partner, investor, supplier, competitor, subsidiary, employs
    relation_subtype = Column(String(100))  # More specific: strategic_partner, minority_investor
    is_bidirectional = Column(Boolean, default=False)  # True for "partners", False for "invests in"

    # Evidence
    source_chunk_id = Column(Integer, ForeignKey('zopk_knowledge_chunks.id'))
    source_fact_id = Column(Integer, ForeignKey('zopk_knowledge_facts.id'))
    evidence_text = Column(Text)  # Quote proving the relation

    # Temporal aspects
    valid_from = Column(Date)  # When relation started
    valid_until = Column(Date)  # When relation ended (NULL = still valid)
    is_current = Column(Boolean, default=True)

    # Strength & confidence
    strength = Column(Integer)  # 1-5, how strong the relation is
    confidence = Column(Numeric(3, 2))  # AI confidence in the relation
    mention_count = Column(Integer, default=1)  # How many times this relation was found

    # Quality
    is_verified = Column(Boolean, default=False)
    verified_by = Column(Integer, ForeignKey('users.id'))

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    entity_a = relationship('ZOPKKnowledgeEntity', foreign_keys=[entity_a_id], backref='relations_as_subject')
    entity_b = relationship('ZOPKKnowledgeEntity', foreign_keys=[entity_b_id], backref='relations_as_object')
    source_chunk = relationship('ZOPKKnowledgeChunk', backref='discovered_relations')
    source_fact = relationship('ZOPKKnowledgeFact', backref='relation_evidence')
    verifier = relationship('User', foreign_keys=[verified_by])

    __table_args__ = (
        UniqueConstraint('entity_a_id', 'entity_b_id', 'relation_type', name='uq_entity_relation'),
    )


class ZOPKKnowledgeExtractionJob(Base):
    """
    Tracks knowledge extraction jobs from approved articles.
    One job per article, tracks progress and results.
    """
    __tablename__ = 'zopk_knowledge_extraction_jobs'

    id = Column(Integer, primary_key=True)
    job_id = Column(String(100), unique=True, nullable=False, index=True)

    # Source
    news_id = Column(Integer, ForeignKey('zopk_news.id'), nullable=False, index=True)

    # Configuration
    extraction_model = Column(String(100))  # gemini-3-flash-preview
    chunk_size = Column(Integer, default=800)  # Target tokens per chunk
    chunk_overlap = Column(Integer, default=100)  # Overlap tokens

    # Results
    chunks_created = Column(Integer, default=0)
    entities_extracted = Column(Integer, default=0)
    facts_extracted = Column(Integer, default=0)
    relations_discovered = Column(Integer, default=0)

    # Costs
    tokens_used = Column(Integer, default=0)
    cost_cents = Column(Numeric(10, 4), default=0)

    # Status
    status = Column(String(20), default='pending')  # pending, running, completed, failed
    error_message = Column(Text)
    progress_percent = Column(Integer, default=0)

    # Timing
    started_at = Column(DateTime)
    completed_at = Column(DateTime)

    # Trigger
    triggered_by = Column(String(50))  # auto (on approval), manual, batch
    triggered_by_user = Column(Integer, ForeignKey('users.id'))

    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    news = relationship('ZOPKNews', backref='extraction_jobs')
    user = relationship('User', foreign_keys=[triggered_by_user])


# ============================================================
# AI USAGE TRACKING MODELS
# ============================================================

class AIUsageLog(Base):
    """
    Individual AI API call logs.
    Tracks tokens, costs, and performance for each Gemini API request.
    """
    __tablename__ = 'ai_usage_logs'

    id = Column(Integer, primary_key=True)

    # Request info
    request_type = Column(String(50), nullable=False)  # chat, news_evaluation, user_creation, image_analysis
    model = Column(String(100), nullable=False)  # gemini-3-flash-preview, gemini-3-pro-preview, etc.

    # Token counts
    tokens_input = Column(Integer, default=0)
    tokens_output = Column(Integer, default=0)
    # Note: tokens_total is a generated column in PostgreSQL

    # Cost (in USD cents for precision)
    cost_cents = Column(Numeric(10, 4), default=0)

    # Context
    user_id = Column(Integer, ForeignKey('users.id'))
    company_id = Column(Integer, ForeignKey('companies.id'))
    related_entity_type = Column(String(50))  # zopk_news, chat_message, company, etc.
    related_entity_id = Column(Integer)

    # Request details
    prompt_length = Column(Integer)
    response_length = Column(Integer)
    response_time_ms = Column(Integer)  # How long the API call took

    # Status
    success = Column(Boolean, default=True)
    error_message = Column(Text)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    user = relationship('User', foreign_keys=[user_id])
    company = relationship('Company', foreign_keys=[company_id])


class AIUsageDaily(Base):
    """
    Pre-aggregated daily AI usage statistics.
    Auto-updated by PostgreSQL trigger on ai_usage_logs insert.
    """
    __tablename__ = 'ai_usage_daily'

    id = Column(Integer, primary_key=True)
    date = Column(Date, unique=True, nullable=False)

    # Request counts by type
    chat_requests = Column(Integer, default=0)
    news_evaluation_requests = Column(Integer, default=0)
    user_creation_requests = Column(Integer, default=0)
    image_analysis_requests = Column(Integer, default=0)
    other_requests = Column(Integer, default=0)
    total_requests = Column(Integer, default=0)

    # Token totals
    total_tokens_input = Column(Integer, default=0)
    total_tokens_output = Column(Integer, default=0)
    total_tokens = Column(Integer, default=0)

    # Cost (in USD cents)
    total_cost_cents = Column(Numeric(10, 4), default=0)

    # Performance
    avg_response_time_ms = Column(Integer)
    error_count = Column(Integer, default=0)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)


class AIRateLimit(Base):
    """
    Rate limit tracking for AI API quota management.
    """
    __tablename__ = 'ai_rate_limits'

    id = Column(Integer, primary_key=True)

    # Limit type
    limit_type = Column(String(50), nullable=False)  # daily, hourly, per_minute
    limit_scope = Column(String(50), nullable=False)  # global, user, ip
    scope_identifier = Column(String(255))  # user_id, ip address, or NULL for global

    # Limits
    max_requests = Column(Integer, nullable=False)
    current_requests = Column(Integer, default=0)

    # Reset
    reset_at = Column(DateTime, nullable=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    __table_args__ = (
        UniqueConstraint('limit_type', 'limit_scope', 'scope_identifier', name='uq_rate_limit'),
    )


# ============================================================
# KRS DATA - OSOBY POWIĄZANE Z FIRMAMI
# ============================================================

class Person(Base):
    """
    Osoby powiązane z firmami (zarząd, wspólnicy, prokurenci).
    Dane pobierane z odpisów KRS.
    """
    __tablename__ = 'people'

    id = Column(Integer, primary_key=True)
    pesel = Column(String(11), unique=True, nullable=True)  # NULL dla osób prawnych
    imiona = Column(String(255), nullable=False)
    nazwisko = Column(String(255), nullable=False)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company_roles = relationship('CompanyPerson', back_populates='person')

    def full_name(self):
        return f"{self.imiona} {self.nazwisko}"

    def __repr__(self):
        return f"<Person {self.full_name()}>"


class CompanyPerson(Base):
    """
    Relacja osoba-firma (zarząd, wspólnicy, prokurenci).
    Umożliwia śledzenie powiązań między osobami a firmami.
    """
    __tablename__ = 'company_people'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False)
    person_id = Column(Integer, ForeignKey('people.id', ondelete='CASCADE'), nullable=False)

    # Rola w firmie
    role = Column(String(50), nullable=False)  # PREZES ZARZĄDU, CZŁONEK ZARZĄDU, WSPÓLNIK
    role_category = Column(String(20), nullable=False)  # zarzad, wspolnik, prokurent

    # Dane dodatkowe (dla wspólników)
    shares_count = Column(Integer)
    shares_value = Column(Numeric(12, 2))
    shares_percent = Column(Numeric(5, 2))

    # Źródło danych
    source = Column(String(100), default='ekrs.ms.gov.pl')
    source_document = Column(String(255))  # np. "odpis_pelny_0000725183.pdf"
    fetched_at = Column(DateTime)

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    company = relationship('Company', backref='people_roles')
    person = relationship('Person', back_populates='company_roles')

    __table_args__ = (
        UniqueConstraint('company_id', 'person_id', 'role_category', 'role', name='uq_company_person_role'),
    )

    def __repr__(self):
        return f"<CompanyPerson {self.person.full_name()} - {self.role} @ {self.company.name}>"


# ============================================================
# KRS AUDIT
# ============================================================

class KRSAudit(Base):
    """
    KRS audit history - tracks PDF downloads and data extraction.
    Each audit represents one extraction run from EKRS.
    """
    __tablename__ = 'krs_audits'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)

    # Audit timing
    audit_date = Column(DateTime, default=datetime.now, nullable=False, index=True)

    # PDF source info
    pdf_filename = Column(String(255))  # np. "odpis_pelny_0000882964.pdf"
    pdf_path = Column(Text)             # full path to stored PDF
    pdf_downloaded_at = Column(DateTime)

    # Extraction status
    status = Column(String(20), default='pending', index=True)  # pending, downloading, parsing, completed, error
    progress_percent = Column(Integer, default=0)
    progress_message = Column(Text)
    error_message = Column(Text)

    # Extracted data summary
    extracted_krs = Column(String(10))
    extracted_nazwa = Column(Text)
    extracted_nip = Column(String(10))
    extracted_regon = Column(String(14))
    extracted_forma_prawna = Column(String(255))
    extracted_data_rejestracji = Column(Date)
    extracted_kapital_zakladowy = Column(Numeric(15, 2))
    extracted_waluta = Column(String(3), default='PLN')
    extracted_liczba_udzialow = Column(Integer)
    extracted_sposob_reprezentacji = Column(Text)

    # Counts for quick stats
    zarzad_count = Column(Integer, default=0)
    wspolnicy_count = Column(Integer, default=0)
    prokurenci_count = Column(Integer, default=0)
    pkd_count = Column(Integer, default=0)

    # Full parsed data as JSON
    parsed_data = Column(JSONB)

    # Audit metadata
    audit_version = Column(String(20), default='1.0')
    audit_source = Column(String(50), default='ekrs.ms.gov.pl')

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationship
    company = relationship('Company', backref='krs_audits')

    def __repr__(self):
        return f'<KRSAudit company_id={self.company_id} status={self.status}>'

    @property
    def status_label(self):
        """Human-readable status label in Polish"""
        labels = {
            'pending': 'Oczekuje',
            'downloading': 'Pobieranie PDF',
            'parsing': 'Przetwarzanie',
            'completed': 'Ukończony',
            'error': 'Błąd'
        }
        return labels.get(self.status, self.status)


class CompanyPKD(Base):
    """
    PKD codes for companies (Polska Klasyfikacja Działalności).
    Multiple PKD codes per company allowed - one is marked as primary.
    """
    __tablename__ = 'company_pkd'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)
    pkd_code = Column(String(10), nullable=False, index=True)  # np. "62.03.Z"
    pkd_description = Column(Text)
    is_primary = Column(Boolean, default=False)  # przeważający PKD
    source = Column(String(50), default='ekrs')  # ekrs, ceidg

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationship
    company = relationship('Company', backref='pkd_codes')

    __table_args__ = (
        UniqueConstraint('company_id', 'pkd_code', name='uq_company_pkd'),
    )

    def __repr__(self):
        primary = ' (główny)' if self.is_primary else ''
        return f'<CompanyPKD {self.pkd_code}{primary}>'


class CompanyFinancialReport(Base):
    """
    Financial reports (sprawozdania finansowe) filed with KRS.
    Tracks report periods and filing dates.
    """
    __tablename__ = 'company_financial_reports'

    id = Column(Integer, primary_key=True)
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='CASCADE'), nullable=False, index=True)
    period_start = Column(Date)
    period_end = Column(Date)
    filed_at = Column(Date)
    report_type = Column(String(50), default='annual')  # annual, quarterly
    source = Column(String(50), default='ekrs')

    # Timestamps
    created_at = Column(DateTime, default=datetime.now)

    # Relationship
    company = relationship('Company', backref='financial_reports')

    __table_args__ = (
        UniqueConstraint('company_id', 'period_start', 'period_end', 'report_type', name='uq_company_financial_report'),
    )

    def __repr__(self):
        return f'<CompanyFinancialReport {self.period_start} - {self.period_end}>'


# ============================================================
# USER BLOCKS - BLOKOWANIE UŻYTKOWNIKÓW
# ============================================================

class UserBlock(Base):
    """
    Blokowanie użytkowników - zablokowany użytkownik nie może wysyłać wiadomości.
    """
    __tablename__ = 'user_blocks'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    blocked_user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    created_at = Column(DateTime, default=datetime.now)
    reason = Column(Text, nullable=True)  # optional reason

    # Relationships
    user = relationship('User', foreign_keys=[user_id], backref='blocks_created')
    blocked_user = relationship('User', foreign_keys=[blocked_user_id], backref='blocked_by')

    def __repr__(self):
        return f'<UserBlock {self.user_id} -> {self.blocked_user_id}>'


# ============================================================
# USER ANALYTICS - SESJE I AKTYWNOŚĆ
# ============================================================

class UserSession(Base):
    """
    Sesje użytkowników portalu.
    Śledzi czas trwania sesji, urządzenie, lokalizację i aktywność.
    """
    __tablename__ = 'user_sessions'

    id = Column(Integer, primary_key=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=True)
    session_id = Column(String(100), unique=True, nullable=False, index=True)

    # Czas sesji
    started_at = Column(DateTime, nullable=False, default=datetime.now)
    ended_at = Column(DateTime, nullable=True)
    last_activity_at = Column(DateTime, nullable=False, default=datetime.now)
    duration_seconds = Column(Integer, nullable=True)

    # Urządzenie
    ip_address = Column(String(45), nullable=True)
    user_agent = Column(Text, nullable=True)
    device_type = Column(String(20), nullable=True)  # desktop, mobile, tablet
    browser = Column(String(50), nullable=True)
    browser_version = Column(String(20), nullable=True)
    os = Column(String(50), nullable=True)
    os_version = Column(String(20), nullable=True)

    # Lokalizacja (z IP)
    country = Column(String(100), nullable=True)
    city = Column(String(100), nullable=True)
    region = Column(String(100), nullable=True)

    # Metryki sesji
    page_views_count = Column(Integer, default=0)
    clicks_count = Column(Integer, default=0)

    # UTM Parameters (kampanie marketingowe)
    utm_source = Column(String(255), nullable=True)  # google, facebook, newsletter
    utm_medium = Column(String(255), nullable=True)  # cpc, email, social, organic
    utm_campaign = Column(String(255), nullable=True)  # nazwa kampanii
    utm_term = Column(String(255), nullable=True)  # słowo kluczowe (PPC)
    utm_content = Column(String(255), nullable=True)  # wariant reklamy

    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    user = relationship('User', backref='analytics_sessions')
    page_views = relationship('PageView', back_populates='session', cascade='all, delete-orphan')

    def __repr__(self):
        return f"<UserSession {self.session_id[:8]}... user={self.user_id}>"


class PageView(Base):
    """
    Wyświetlenia stron przez użytkowników.
    Śledzi odwiedzone strony i czas spędzony na każdej z nich.
    """
    __tablename__ = 'page_views'

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey('user_sessions.id', ondelete='CASCADE'), nullable=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)

    # Strona
    url = Column(String(2000), nullable=False)
    path = Column(String(500), nullable=False, index=True)
    page_title = Column(String(500), nullable=True)
    referrer = Column(String(2000), nullable=True)

    # Czas
    viewed_at = Column(DateTime, nullable=False, default=datetime.now, index=True)
    time_on_page_seconds = Column(Integer, nullable=True)

    # Scroll depth (%)
    scroll_depth_percent = Column(Integer, nullable=True)  # 0-100

    # Performance metrics (Web Vitals)
    dom_content_loaded_ms = Column(Integer, nullable=True)
    load_time_ms = Column(Integer, nullable=True)
    first_paint_ms = Column(Integer, nullable=True)
    first_contentful_paint_ms = Column(Integer, nullable=True)

    # Kontekst
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='SET NULL'), nullable=True)

    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    session = relationship('UserSession', back_populates='page_views')
    clicks = relationship('UserClick', back_populates='page_view', cascade='all, delete-orphan')

    def __repr__(self):
        return f"<PageView {self.path}>"


class UserClick(Base):
    """
    Kliknięcia elementów na stronach.
    Śledzi interakcje użytkowników z elementami UI.
    """
    __tablename__ = 'user_clicks'

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey('user_sessions.id', ondelete='CASCADE'), nullable=True)
    page_view_id = Column(Integer, ForeignKey('page_views.id', ondelete='CASCADE'), nullable=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)

    # Element kliknięty
    element_type = Column(String(50), nullable=True)  # button, link, card, nav, form
    element_id = Column(String(100), nullable=True)
    element_text = Column(String(255), nullable=True)
    element_class = Column(String(500), nullable=True)
    target_url = Column(String(2000), nullable=True)

    # Pozycja kliknięcia
    x_position = Column(Integer, nullable=True)
    y_position = Column(Integer, nullable=True)

    clicked_at = Column(DateTime, nullable=False, default=datetime.now, index=True)

    # Relationships
    page_view = relationship('PageView', back_populates='clicks')

    def __repr__(self):
        return f"<UserClick {self.element_type} at {self.clicked_at}>"


class AnalyticsDaily(Base):
    """
    Dzienne statystyki agregowane.
    Automatycznie aktualizowane przez trigger PostgreSQL.
    """
    __tablename__ = 'analytics_daily'

    id = Column(Integer, primary_key=True)
    date = Column(Date, unique=True, nullable=False, index=True)

    # Sesje
    total_sessions = Column(Integer, default=0)
    unique_users = Column(Integer, default=0)
    new_users = Column(Integer, default=0)
    returning_users = Column(Integer, default=0)
    anonymous_sessions = Column(Integer, default=0)

    # Aktywność
    total_page_views = Column(Integer, default=0)
    total_clicks = Column(Integer, default=0)
    avg_session_duration_seconds = Column(Integer, nullable=True)
    avg_pages_per_session = Column(Numeric(5, 2), nullable=True)

    # Urządzenia
    desktop_sessions = Column(Integer, default=0)
    mobile_sessions = Column(Integer, default=0)
    tablet_sessions = Column(Integer, default=0)

    # Engagement
    bounce_rate = Column(Numeric(5, 2), nullable=True)

    # Nowe metryki (Analytics Expansion 2026-01-30)
    conversions_count = Column(Integer, default=0)
    searches_count = Column(Integer, default=0)
    searches_no_results = Column(Integer, default=0)
    avg_scroll_depth = Column(Numeric(5, 2), nullable=True)
    js_errors_count = Column(Integer, default=0)

    # Rozkłady (JSONB)
    utm_breakdown = Column(JSONBType, nullable=True)  # {"google": 10, "facebook": 5}
    conversions_breakdown = Column(JSONBType, nullable=True)  # {"register": 2, "contact_click": 15}

    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    def __repr__(self):
        return f"<AnalyticsDaily {self.date}>"


class PopularPagesDaily(Base):
    """
    Popularne strony - dzienne agregaty.
    """
    __tablename__ = 'popular_pages_daily'

    id = Column(Integer, primary_key=True)
    date = Column(Date, nullable=False, index=True)
    path = Column(String(500), nullable=False)
    page_title = Column(String(500), nullable=True)

    views_count = Column(Integer, default=0)
    unique_visitors = Column(Integer, default=0)
    avg_time_seconds = Column(Integer, nullable=True)

    __table_args__ = (
        UniqueConstraint('date', 'path', name='uq_popular_pages_date_path'),
    )

    def __repr__(self):
        return f"<PopularPagesDaily {self.date} {self.path}>"


class SearchQuery(Base):
    """
    Historia wyszukiwań użytkowników w portalu.
    Śledzi zapytania, wyniki i interakcje.
    Created: 2026-01-30
    """
    __tablename__ = 'search_queries'

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey('user_sessions.id', ondelete='SET NULL'), nullable=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)

    # Zapytanie
    query = Column(String(500), nullable=False)
    query_normalized = Column(String(500), nullable=True)  # lowercase, bez znaków specjalnych

    # Wyniki
    results_count = Column(Integer, default=0)
    has_results = Column(Boolean, default=True)

    # Interakcja z wynikami
    clicked_result_position = Column(Integer, nullable=True)  # 1-based
    clicked_company_id = Column(Integer, ForeignKey('companies.id', ondelete='SET NULL'), nullable=True)

    # Kontekst
    search_type = Column(String(50), default='main')  # main, chat, autocomplete
    filters_used = Column(JSONBType, nullable=True)  # {"category": "IT", "city": "Wejherowo"}

    # Timing
    searched_at = Column(DateTime, nullable=False, default=datetime.now)
    time_to_click_ms = Column(Integer, nullable=True)

    created_at = Column(DateTime, default=datetime.now)

    def __repr__(self):
        return f"<SearchQuery '{self.query[:30]}...' results={self.results_count}>"


class ConversionEvent(Base):
    """
    Kluczowe konwersje: rejestracje, kontakty z firmami, RSVP na wydarzenia.
    Created: 2026-01-30
    """
    __tablename__ = 'conversion_events'

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey('user_sessions.id', ondelete='SET NULL'), nullable=True)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)

    # Typ konwersji
    event_type = Column(String(50), nullable=False)  # register, login, contact_click, rsvp, message, classified
    event_category = Column(String(50), nullable=True)  # engagement, acquisition, activation

    # Kontekst
    company_id = Column(Integer, ForeignKey('companies.id', ondelete='SET NULL'), nullable=True)
    target_type = Column(String(50), nullable=True)  # email, phone, website, rsvp_event
    target_value = Column(String(500), nullable=True)

    # Źródło konwersji
    source_page = Column(String(500), nullable=True)
    referrer = Column(String(500), nullable=True)

    # Dodatkowe dane
    event_metadata = Column(JSONBType, nullable=True)

    # Timing
    converted_at = Column(DateTime, nullable=False, default=datetime.now)
    created_at = Column(DateTime, default=datetime.now)

    # Relationships
    company = relationship('Company', backref='conversion_events')

    def __repr__(self):
        return f"<ConversionEvent {self.event_type} at {self.converted_at}>"


class JSError(Base):
    """
    Błędy JavaScript zgłaszane z przeglądarek użytkowników.
    Created: 2026-01-30
    """
    __tablename__ = 'js_errors'

    id = Column(Integer, primary_key=True)
    session_id = Column(Integer, ForeignKey('user_sessions.id', ondelete='SET NULL'), nullable=True)

    # Błąd
    message = Column(Text, nullable=False)
    source = Column(String(500), nullable=True)  # URL pliku JS
    lineno = Column(Integer, nullable=True)
    colno = Column(Integer, nullable=True)
    stack = Column(Text, nullable=True)

    # Kontekst
    url = Column(String(2000), nullable=True)
    user_agent = Column(String(500), nullable=True)

    # Agregacja
    error_hash = Column(String(64), nullable=True)  # SHA256 dla grupowania

    occurred_at = Column(DateTime, nullable=False, default=datetime.now)
    created_at = Column(DateTime, default=datetime.now)

    def __repr__(self):
        return f"<JSError '{self.message[:50]}...'>"


class PopularSearchesDaily(Base):
    """
    Popularne wyszukiwania - dzienne agregaty.
    Created: 2026-01-30
    """
    __tablename__ = 'popular_searches_daily'

    id = Column(Integer, primary_key=True)
    date = Column(Date, nullable=False, index=True)
    query_normalized = Column(String(500), nullable=False)

    search_count = Column(Integer, default=0)
    unique_users = Column(Integer, default=0)
    click_count = Column(Integer, default=0)
    avg_results_count = Column(Numeric(10, 2), nullable=True)

    __table_args__ = (
        UniqueConstraint('date', 'query_normalized', name='uq_popular_searches_date_query'),
    )

    def __repr__(self):
        return f"<PopularSearchesDaily {self.date} '{self.query_normalized}'>"


class HourlyActivity(Base):
    """
    Aktywność wg godziny - dla analizy wzorców czasowych.
    Created: 2026-01-30
    """
    __tablename__ = 'hourly_activity'

    id = Column(Integer, primary_key=True)
    date = Column(Date, nullable=False, index=True)
    hour = Column(Integer, nullable=False)  # 0-23

    sessions_count = Column(Integer, default=0)
    page_views_count = Column(Integer, default=0)
    unique_users = Column(Integer, default=0)

    __table_args__ = (
        UniqueConstraint('date', 'hour', name='uq_hourly_activity_date_hour'),
    )

    def __repr__(self):
        return f"<HourlyActivity {self.date} {self.hour}:00>"


# ============================================================
# EMAIL LOGGING
# ============================================================

class EmailLog(Base):
    """
    Log wszystkich wysłanych emaili systemowych.

    Śledzi:
    - Emaile rejestracyjne (weryfikacja)
    - Emaile resetowania hasła
    - Powiadomienia systemowe
    - Status dostarczenia

    Created: 2026-01-14
    """
    __tablename__ = 'email_logs'

    id = Column(Integer, primary_key=True)

    # Dane emaila
    email_type = Column(String(50), nullable=False, index=True)  # welcome, password_reset, notification
    recipient_email = Column(String(255), nullable=False, index=True)
    recipient_name = Column(String(255), nullable=True)
    subject = Column(String(500), nullable=False)

    # Powiązanie z użytkownikiem (opcjonalne)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)

    # Status
    status = Column(String(20), default='pending', index=True)  # pending, sent, failed
    error_message = Column(Text, nullable=True)

    # Metadane
    sender_email = Column(String(255), nullable=True)
    ip_address = Column(String(45), nullable=True)  # IP requestu (jeśli dostępne)

    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow)
    sent_at = Column(DateTime, nullable=True)

    # Relacje
    user = relationship('User', backref='email_logs')

    def __repr__(self):
        return f"<EmailLog {self.id} {self.email_type} -> {self.recipient_email} ({self.status})>"


# ============================================================
# SECURITY & AUDIT
# ============================================================

class AuditLog(Base):
    """
    Audit log dla śledzenia działań administracyjnych.

    Śledzi wszystkie wrażliwe operacje wykonywane przez adminów:
    - Moderacja newsów (approve/reject)
    - Zmiany składek członkowskich
    - Edycja profili firm
    - Zmiany uprawnień użytkowników
    - Operacje na wydarzeniach

    Created: 2026-01-14
    """
    __tablename__ = 'audit_logs'

    id = Column(Integer, primary_key=True)

    # Kto wykonał akcję
    user_id = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
    user_email = Column(String(255), nullable=False)  # Zachowane nawet po usunięciu usera

    # Co zostało wykonane
    action = Column(String(100), nullable=False, index=True)  # np. 'news.approve', 'company.edit', 'user.ban'
    entity_type = Column(String(50), nullable=False, index=True)  # np. 'news', 'company', 'user', 'event'
    entity_id = Column(Integer, nullable=True)  # ID encji której dotyczy akcja
    entity_name = Column(String(255), nullable=True)  # Nazwa encji (dla czytelności)

    # Szczegóły
    details = Column(JSONBType, nullable=True)  # Dodatkowe dane: old_value, new_value, reason

    # Kontekst requestu
    ip_address = Column(String(45), nullable=True)
    user_agent = Column(String(500), nullable=True)
    request_path = Column(String(500), nullable=True)

    # Timestamp
    created_at = Column(DateTime, default=datetime.utcnow, index=True)

    # Relacje
    user = relationship('User', backref='audit_logs')

    def __repr__(self):
        return f"<AuditLog {self.id} {self.user_email} {self.action} on {self.entity_type}:{self.entity_id}>"


class SecurityAlert(Base):
    """
    Alerty bezpieczeństwa wysyłane emailem.

    Śledzi:
    - Zbyt wiele nieudanych logowań
    - Próby dostępu do honeypotów
    - Podejrzane wzorce aktywności
    - Blokady kont

    Created: 2026-01-14
    """
    __tablename__ = 'security_alerts'

    id = Column(Integer, primary_key=True)

    # Typ alertu
    alert_type = Column(String(50), nullable=False, index=True)
    # Typy: 'brute_force', 'honeypot_hit', 'account_locked', 'suspicious_activity', 'geo_blocked'

    severity = Column(String(20), nullable=False, default='medium')  # low, medium, high, critical

    # Kontekst
    ip_address = Column(String(45), nullable=True, index=True)
    user_email = Column(String(255), nullable=True)
    details = Column(JSONBType, nullable=True)  # Dodatkowe dane

    # Status alertu
    status = Column(String(20), default='new', index=True)  # new, acknowledged, resolved
    acknowledged_by = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'), nullable=True)
    acknowledged_at = Column(DateTime, nullable=True)
    resolution_note = Column(Text, nullable=True)

    # Email notification
    email_sent = Column(Boolean, default=False)
    email_sent_at = Column(DateTime, nullable=True)

    # Timestamps
    created_at = Column(DateTime, default=datetime.utcnow, index=True)
    updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)

    # Relacje
    acknowledger = relationship('User', foreign_keys=[acknowledged_by])

    def __repr__(self):
        return f"<SecurityAlert {self.id} {self.alert_type} ({self.severity}) from {self.ip_address}>"


# ============================================================
# ANNOUNCEMENTS (Ogłoszenia dla członków)
# ============================================================

class Announcement(Base):
    """
    Ogłoszenia i aktualności dla członków Norda Biznes.
    Obsługuje różne kategorie: ogólne, wydarzenia, okazje biznesowe, od członków.
    """
    __tablename__ = 'announcements'

    id = Column(Integer, primary_key=True)
    title = Column(String(300), nullable=False)
    slug = Column(String(300), unique=True, index=True)
    excerpt = Column(String(500))  # Krótki opis do listy
    content = Column(Text, nullable=False)  # Pełna treść (HTML)

    # Kategoryzacja (obsługa wielu kategorii)
    categories = Column(ARRAY(String), default=[])  # Tablica kategorii
    # Wartości: internal, external, event, opportunity, partnership
    # Stare pole dla kompatybilności wstecznej (do usunięcia po migracji)
    category = Column(String(50), default='internal')

    # Media
    image_url = Column(String(1000))
    external_link = Column(String(1000))  # Link do zewnętrznego źródła

    # Publikacja
    status = Column(String(20), default='draft', index=True)
    # Wartości: draft, published, archived
    published_at = Column(DateTime)
    expires_at = Column(DateTime)  # Opcjonalne wygaśnięcie

    # Wyróżnienie
    is_featured = Column(Boolean, default=False)
    is_pinned = Column(Boolean, default=False)

    # Statystyki
    views_count = Column(Integer, default=0)

    # Audyt
    created_by = Column(Integer, ForeignKey('users.id'))
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    author = relationship('User', foreign_keys=[created_by])
    readers = relationship('AnnouncementRead', back_populates='announcement', cascade='all, delete-orphan')

    # Constants
    CATEGORIES = ['internal', 'external', 'event', 'opportunity', 'partnership']
    CATEGORY_LABELS = {
        'internal': 'Wewnętrzne',
        'external': 'Zewnętrzne',
        'event': 'Wydarzenie',
        'opportunity': 'Okazja biznesowa',
        'partnership': 'Partnerstwo'
    }
    STATUSES = ['draft', 'published', 'archived']
    STATUS_LABELS = {
        'draft': 'Szkic',
        'published': 'Opublikowane',
        'archived': 'Zarchiwizowane'
    }

    @property
    def category_label(self):
        """Zwraca polską etykietę pierwszej kategorii (kompatybilność wsteczna)"""
        if self.categories:
            return self.CATEGORY_LABELS.get(self.categories[0], self.categories[0])
        return self.CATEGORY_LABELS.get(self.category, self.category)

    @property
    def categories_labels(self):
        """Zwraca listę polskich etykiet wszystkich kategorii"""
        if self.categories:
            return [self.CATEGORY_LABELS.get(cat, cat) for cat in self.categories]
        return [self.CATEGORY_LABELS.get(self.category, self.category)]

    def has_category(self, category):
        """Sprawdza czy ogłoszenie ma daną kategorię"""
        if self.categories:
            return category in self.categories
        return self.category == category

    @property
    def status_label(self):
        """Zwraca polską etykietę statusu"""
        return self.STATUS_LABELS.get(self.status, self.status)

    @property
    def is_active(self):
        """Sprawdza czy ogłoszenie jest aktywne (opublikowane i nie wygasło)"""
        if self.status != 'published':
            return False
        if self.expires_at and self.expires_at < datetime.now():
            return False
        return True

    def __repr__(self):
        return f"<Announcement {self.id} '{self.title[:50]}' ({self.status})>"


class AnnouncementRead(Base):
    """
    Śledzenie odczytów ogłoszeń (seen by).
    Zapisuje kto i kiedy przeczytał dane ogłoszenie.
    """
    __tablename__ = 'announcement_reads'

    id = Column(Integer, primary_key=True)
    announcement_id = Column(Integer, ForeignKey('announcements.id', ondelete='CASCADE'), nullable=False)
    user_id = Column(Integer, ForeignKey('users.id', ondelete='CASCADE'), nullable=False)
    read_at = Column(DateTime, default=datetime.now)

    # Relationships
    announcement = relationship('Announcement', back_populates='readers')
    user = relationship('User')

    # Unique constraint
    __table_args__ = (
        UniqueConstraint('announcement_id', 'user_id', name='uq_announcement_user_read'),
    )

    def __repr__(self):
        return f"<AnnouncementRead announcement={self.announcement_id} user={self.user_id}>"


# ============================================================
# EXTERNAL CONTACTS (Kontakty zewnętrzne)
# ============================================================

class ExternalContact(Base):
    """
    Baza kontaktów zewnętrznych - urzędy, instytucje, partnerzy projektów.
    Dostępna dla wszystkich zalogowanych członków Norda Biznes.
    """
    __tablename__ = 'external_contacts'

    id = Column(Integer, primary_key=True)

    # Dane osobowe
    first_name = Column(String(100), nullable=False)
    last_name = Column(String(100), nullable=False)
    position = Column(String(200))  # Stanowisko (opcjonalne)
    photo_url = Column(String(500))  # Zdjęcie osoby (opcjonalne)

    # Dane kontaktowe
    phone = Column(String(50))
    phone_secondary = Column(String(50))  # Drugi numer telefonu
    email = Column(String(255))
    website = Column(String(500))  # Strona osobista/wizytówka

    # Social Media
    linkedin_url = Column(String(500))
    facebook_url = Column(String(500))
    twitter_url = Column(String(500))

    # Organizacja
    organization_name = Column(String(300), nullable=False)
    organization_type = Column(String(50), default='other')
    # Typy: government (urząd), agency (agencja), company (firma), ngo (organizacja), university (uczelnia), other

    organization_address = Column(String(500))
    organization_website = Column(String(500))
    organization_logo_url = Column(String(500))

    # Kontekst/Projekt
    project_name = Column(String(300))  # Nazwa projektu (Tytani, EJ Choczewo, itp.)
    project_description = Column(Text)  # Krótki opis kontekstu

    # Źródło kontaktu
    source_type = Column(String(50))  # announcement, forum_post, manual
    source_id = Column(Integer)  # ID ogłoszenia lub wpisu (opcjonalne)
    source_url = Column(String(500))  # URL do źródła

    # Powiązane linki (artykuły, strony, dokumenty) - JSON array
    # Format: [{"title": "Artykuł o...", "url": "https://...", "type": "article"}, ...]
    related_links = Column(PG_JSONB, default=list)

    # Tagi do wyszukiwania
    tags = Column(String(500))  # Tagi oddzielone przecinkami

    # Notatki
    notes = Column(Text)

    # Audyt
    created_by = Column(Integer, ForeignKey('users.id', ondelete='SET NULL'))
    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Status
    is_active = Column(Boolean, default=True)
    is_verified = Column(Boolean, default=False)  # Zweryfikowany przez admina/moderatora

    # Relationships
    creator = relationship('User', foreign_keys=[created_by])

    # Constants
    ORGANIZATION_TYPES = ['government', 'agency', 'company', 'ngo', 'university', 'other']
    ORGANIZATION_TYPE_LABELS = {
        'government': 'Urząd',
        'agency': 'Agencja',
        'company': 'Firma',
        'ngo': 'Organizacja pozarządowa',
        'university': 'Uczelnia',
        'other': 'Inne'
    }
    SOURCE_TYPES = ['announcement', 'forum_post', 'manual']

    @property
    def full_name(self):
        return f"{self.first_name} {self.last_name}"

    @property
    def organization_type_label(self):
        return self.ORGANIZATION_TYPE_LABELS.get(self.organization_type, self.organization_type)

    @property
    def tags_list(self):
        """Zwraca tagi jako listę."""
        if not self.tags:
            return []
        return [tag.strip() for tag in self.tags.split(',') if tag.strip()]

    @property
    def has_social_media(self):
        """Sprawdza czy kontakt ma jakiekolwiek social media."""
        return bool(self.linkedin_url or self.facebook_url or self.twitter_url)

    @property
    def has_contact_info(self):
        """Sprawdza czy kontakt ma dane kontaktowe."""
        return bool(self.phone or self.email or self.website)

    def __repr__(self):
        return f"<ExternalContact {self.full_name} @ {self.organization_name}>"


# ============================================================
# ZOPK MILESTONES (Timeline)
# ============================================================

class ZOPKMilestone(Base):
    """
    Kamienie milowe projektu ZOPK dla wizualizacji timeline.
    """
    __tablename__ = 'zopk_milestones'

    id = Column(Integer, primary_key=True)
    title = Column(String(500), nullable=False)
    description = Column(Text)

    # Kategoria: nuclear, offshore, infrastructure, defense, other
    category = Column(String(50), default='other')

    # Daty
    target_date = Column(Date)  # Planowana data
    actual_date = Column(Date)  # Rzeczywista data (jeśli zakończone)

    # Status: planned, in_progress, completed, delayed, cancelled
    status = Column(String(20), default='planned')

    # Źródło informacji
    source_url = Column(String(1000))
    source_news_id = Column(Integer, ForeignKey('zopk_news.id'))

    # Wyświetlanie
    icon = Column(String(50))  # emoji lub ikona
    color = Column(String(20))  # kolor dla timeline
    is_featured = Column(Boolean, default=False)
    is_verified = Column(Boolean, default=True)  # Czy zatwierdzony do wyświetlenia

    created_at = Column(DateTime, default=datetime.now)
    updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)

    # Relationships
    source_news = relationship('ZOPKNews', backref='milestones')


# ============================================================
# DATABASE INITIALIZATION
# ============================================================

def init_db():
    """Initialize database - create all tables"""
    # Import all models to ensure they're registered
    # (already done at module level)

    # Create tables (only creates if they don't exist)
    Base.metadata.create_all(bind=engine)

    print("Database tables created successfully!")


def drop_all_tables():
    """Drop all tables - USE WITH CAUTION!"""
    Base.metadata.drop_all(bind=engine)
    print("All tables dropped!")


if __name__ == '__main__':
    # Test database connection
    try:
        init_db()
        print("✅ Database initialized successfully")

        # Test query
        db = SessionLocal()
        try:
            count = db.query(Company).count()
            print(f"✅ Database connected. Found {count} companies.")
        finally:
            db.close()

    except Exception as e:
        print(f"❌ Database error: {e}")
