U
    !rh                     @   s   d Z ddlmZ ddlmZ ddlmZmZm	Z	m
Z
mZ ddlmZ ddlmZ ddlmZ ddlmZmZ dd	lmZ G d
d deZG dd deeZG dd deZdS )a  
AgencyType Model

This module contains the AgencyType model which represents different categories
of advertising agencies in the system. It provides a taxonomy for classifying
agencies based on their specialization, size, and service offerings.

Author: Senior Developer
Created: 2025-08-12
Version: 1.0

Dependencies:
    - Django 4.2+
    - django.utils.translation for internationalization
    - apps.common.models.BaseModel for shared functionality
    )models)gettext_lazy)FileExtensionValidatorMinValueValidatorMaxValueValidatorEmailValidatorURLValidator)ValidationError)timezone)User)	BaseModelAddressModel)agency_logo_upload_pathc                       s  e Zd ZdZejddededddZejdededd	Z	ejd
dededddZ
ejdededddZejdededddZG dd dZdd Zdd Z fddZ fddZd d! Zd"d# Zd$d% Zd/d'd(Zd)d* Zed+d, Zed-d. Z  ZS )0
AgencyTypeaj  
        Model representing different types of advertising agencies.
        
        This model serves as a categorization system for agencies, allowing
        the platform to organize and filter agencies based on their specialization,
        size, and service offerings. It's designed to be flexible and extensible
        to accommodate various agency business models.
        
        Business Logic:
        - Agencies are categorized to help clients find the right type of agency
        - Premium types may have special features or higher visibility
        - Sort order allows for strategic positioning of agency types
        - Color coding enables consistent UI representation
        
        Relationships:
        - One AgencyType can have many Agencies (One-to-Many)
        - Uses PROTECT on delete to maintain referential integrity
        
        Attributes:
            name (CharField): The display name of the agency type
            description (TextField): Detailed description of the agency type
            color_code (CharField): Hex color code for UI representation
            sort_order (PositiveIntegerField): Display order priority
            is_premium (BooleanField): Premium type flag for special features
            
        Inherited from BaseModel:
            id (AutoField): Primary key
            created_at (DateTimeField): Record creation timestamp
            updated_at (DateTimeField): Last modification timestamp
            is_deleted (BooleanField): Soft delete flag
            
        Example Usage:
            # Create a new agency type
            agency_type = AgencyType.objects.create(
                name="Digital Marketing",
                description="Specialized in digital advertising and online marketing",
                color_code="#007bff",
                sort_order=1,
                is_premium=True
            )
            
            # Query premium agency types
            premium_types = AgencyType.objects.filter(is_premium=True)
            
            # Get agencies of a specific type
            digital_agencies = agency_type.agencies.filter(is_active=True)
    d   TzAgency Type NamezThe name of the agency type (e.g., Full Service, Digital, Creative). This name will be displayed throughout the platform and should be descriptive and professional.)
max_lengthuniqueverbose_name	help_textdb_indexDescriptionzDetailed description of what this agency type represents, including typical services, client types, and characteristics. This helps agencies and clients understand the category better.blankr   r      z#007bffz
Color CodezHex color code for UI representation (e.g., #007bff). This color will be used in charts, badges, and other UI elements to visually distinguish this agency type.)r   defaultr   r   r   r   z
Sort OrderzOrder in which agency types should be displayed. Lower numbers appear first. Use this to strategically position important agency types at the top of lists.r   r   r   r   FzPremium TypezWhether this is a premium agency type with special features such as enhanced visibility, priority placement, or exclusive access to certain platform features.c                   @   s   e Zd ZdZedZedZddgZdZe	j
ddgdd	e	j
dge	jd
dddgZe	je	jdddde	je	jddddgZdS )zAgencyType.Metaz
        Meta class defining model behavior and database configuration.
        
        This configuration optimizes the model for performance and usability
        while ensuring proper internationalization and database structure.
        Agency TypezAgency Types
sort_ordernameZagencies_agency_type
is_premiumZidx_premium_sort)fieldsr   F)
is_deletedZidx_active_premium)r    	conditionr   r   )Zsort_order__gteZcheck_sort_order_positive)checkr   z^#[0-9A-Fa-f]{6}$)Zcolor_code__regexZcheck_color_code_formatN)__name__
__module____qualname____doc___r   verbose_name_pluralorderingdb_tabler   IndexQindexesCheckConstraintconstraints r1   r1   8/var/www/html/Focus/src/apps/agencies/models/agencies.pyMeta   s*   


r3   c                 C   s   | j S )a  
        String representation of the agency type.
        
        Returns the name of the agency type, which is the most meaningful
        identifier for users and administrators.
        
        Returns:
            str: The name of the agency type
            
        Example:
            >>> agency_type = AgencyType(name="Digital Marketing")
            >>> str(agency_type)
            "Digital Marketing"
        r   selfr1   r1   r2   __str__   s    zAgencyType.__str__c              	   C   s&   d| j  d| j d| j d| j d	S )a	  
        Developer-friendly string representation.
        
        Provides detailed information about the instance for debugging
        and development purposes.
        
        Returns:
            str: Detailed representation including key attributes
        z<AgencyType(id=z, name='z', premium=z, order=z)>)pkr   r   r   r5   r1   r1   r2   __repr__   s    $zAgencyType.__repr__c                    s   t    | jrV| j | _| js2tdtditdd | jD sVtdtdi| jr| j  | _ddl	}|
d| jstd	td
i| jrt| jdkrtdtdidS )a  
        Custom model validation logic.
        
        Performs validation that goes beyond simple field constraints,
        ensuring business rules are followed and data integrity is maintained.
        
        Raises:
            ValidationError: If validation fails
            
        Validation Rules:
        1. Name must not be empty or just whitespace
        2. Color code must be a valid hex color
        3. Description should not exceed reasonable length for display
        r   z4Agency type name cannot be empty or just whitespace.c                 s   s   | ]}|  V  qd S )N)isalnum).0cr1   r1   r2   	<genexpr>  s     z#AgencyType.clean.<locals>.<genexpr>z<Agency type name must contain at least one letter or number.r   Nz^#[0-9A-F]{6}$
color_codezjColor code must be in hex format (e.g., #007BFF). Use exactly 6 hexadecimal characters after the # symbol.i  descriptionzdDescription is too long. Please keep it under 2000 characters for better display in user interfaces.)supercleanr   stripr	   r(   anyr>   upperrematchr?   len)r6   rE   	__class__r1   r2   rA      s<    
    zAgencyType.cleanc                    s   |    t j|| dS )aM  
        Custom save method with additional processing.
        
        Ensures validation is run and performs any necessary
        pre-save processing.
        
        Args:
            *args: Variable length argument list passed to parent save()
            **kwargs: Arbitrary keyword arguments passed to parent save()
        N)
full_cleanr@   save)r6   argskwargsrH   r1   r2   rK   #  s    zAgencyType.savec                 C   s
   | j  S )z
        Get the total number of agencies of this type.
        
        Returns:
            int: Count of agencies associated with this type
            
        Example:
            >>> agency_type.get_agencies_count()
            15
        )agenciescountr5   r1   r1   r2   get_agencies_count8  s    zAgencyType.get_agencies_countc                 C   s   | j jddd S )aH  
        Get the number of active agencies of this type.
        
        Only counts agencies that are marked as active and not deleted.
        
        Returns:
            int: Count of active agencies of this type
            
        Example:
            >>> agency_type.get_active_agencies_count()
            12
        TF)	is_activer!   rN   filterrO   r5   r1   r1   r2   get_active_agencies_countE  s    z$AgencyType.get_active_agencies_countc                 C   s   | j jdddd S )z
        Get the number of premium agencies of this type.
        
        Counts agencies that are both active and marked as premium/featured.
        
        Returns:
            int: Count of premium agencies of this type
        TF)rQ   r!   is_featuredrR   r5   r1   r1   r2   get_premium_agencies_countT  s
    	z%AgencyType.get_premium_agencies_count
   c                 C   s   |   |kS )a  
        Check if this agency type is popular based on agency count.
        
        Args:
            threshold (int): Minimum number of agencies to be considered popular
            
        Returns:
            bool: True if the agency type has at least threshold agencies
            
        Example:
            >>> agency_type.is_popular(threshold=5)
            True
        )rT   )r6   	thresholdr1   r1   r2   
is_popularc  s    zAgencyType.is_popularc                    sZ   | j rt| j dkrdS z&| j dd  t fdddD W S  tk
rT   Y dS X dS )a,  
        Convert hex color code to RGB tuple.
        
        Returns:
            tuple: RGB values as (red, green, blue) integers (0-255)
            
        Example:
            >>> agency_type.color_code = "#007BFF"
            >>> agency_type.get_color_rgb()
            (0, 123, 255)
        r   )r   {         Nc                 3   s$   | ]}t  ||d   dV  qdS )      N)int)r;   iZ	hex_colorr1   r2   r=     s     z+AgencyType.get_color_rgb.<locals>.<genexpr>)r   r]      )r>   rG   tuple
ValueErrorr5   r1   ra   r2   get_color_rgbs  s    zAgencyType.get_color_rgbc              
   C   sr   t dt dddddt dt dd	d
ddt dt dddddt dt dddddt dt dddddgS )a  
        Get a list of default agency types for system initialization.
        
        This is useful for data migration scripts or initial system setup.
        
        Returns:
            list: List of dictionaries with agency type data
            
        Example:
            >>> AgencyType.get_default_types()
            [{'name': 'Full Service', 'description': '...', ...}, ...]
        Full ServicezSComprehensive advertising services including strategy, creative, media, and digitalz#007BFFr\   T)r   r?   r>   r   r   Digital MarketingzFSpecialized in digital advertising, social media, and online marketingz#28A745r]   zCreative Agencyz<Focus on creative development, branding, and design servicesz#DC3545   FzMedia Agencyz7Specialized in media planning, buying, and optimizationz#FFC107rb   ZBoutiquez0Small, specialized agencies with niche expertisez#6F42C1   )r(   )clsr1   r1   r2   get_default_types  s>    zAgencyType.get_default_typesc                 C   sH   g }|   D ]6}| jj|d d }|s| jjf |}|| q|S )a  
        Create default agency types if they don't exist.
        
        This method is safe to run multiple times as it checks for
        existing types before creating new ones.
        
        Returns:
            list: List of created AgencyType instances
            
        Example:
            >>> created_types = AgencyType.create_default_types()
            >>> len(created_types)
            3  # Number of new types created
        r   r4   )rk   objectsrS   firstcreateappend)rj   Zcreated_typesZ	type_dataZexisting_typeagency_typer1   r1   r2   create_default_types  s    zAgencyType.create_default_types)rW   )r$   r%   r&   r'   r   	CharFieldr(   r   	TextFieldr?   r>   PositiveIntegerFieldr   BooleanFieldr   r3   r7   r9   rA   rK   rP   rT   rV   rY   re   classmethodrk   rq   __classcell__r1   r1   rH   r2   r   '   sp   4
29

3r   c                   @   s  e Zd ZdZdedfdedfdedfded	fd
edfgZdedfdedfdedfdedfdedfdedfdedfdedfdedfdedfg
Zejd ed!ed"d#d$Z	ejd d#ed%ed&d'Z
ejd(ejd)ed*ed+d#d,Zejd#ed-ed.d/Zejed#d#ed0ed1ed2d3d4d5d6gd7gd8Zejd#ed9ed:e gd;Zejd<d#ed=ed>d'Zejed?ed@e gd#dAZejd#d#edBedCgedDedEd#dFZejd<ededGedHd#dIZejd#d#edJedKdLZ ej!e"d#edMedNdOZ#ej$dPedQedRd#dSZ%ej$dPedTedUd#dSZ&ej$d#edVedWd#dSZ'ejdXdYedZed[d\Z(ejd]d^ed_ed`d\Z)eje*ej+daedbedcd#d,Z,G ddde deZ-dfdg Z.dhdi Z/djdk Z0e1dldm Z2dnS )oAgencyaA  
    Model representing an advertising agency in the platform.
    
    This is the core model for agency management, containing all essential
    information about an advertising agency including business details,
    contact information, team structure, and operational settings.
    
    Business Logic:
    - Each agency has one owner who has full administrative rights
    - Agencies can have multiple team members with different roles
    - Agencies can manage multiple brands and their campaigns
    - Support for verification system to build trust
    - Premium features for enhanced visibility and functionality
    - Geographic information for location-based matching
    
    Relationships:
    - Belongs to one AgencyType (Many-to-One)
    - Owned by one User (Many-to-One)
    - Has many AgencyTeamMembers (One-to-Many)
    - Has many Brands (One-to-Many)
    - Has many Campaigns through Brands (One-to-Many-to-Many)
    
    Key Features:
    - Comprehensive business profile
    - Team management with role-based permissions
    - File upload handling for logos
    - Address management through AddressModel
    - Internationalization support
    - Performance optimization through indexing
    - Data validation and business rule enforcement
    
    Example Usage:
        # Create a new agency
        agency = Agency.objects.create(
            name="Creative Solutions Ltd",
            email="info@creativesolutions.com",
            agency_type=agency_type,
            owner=user,
            description="Full-service creative agency specializing in digital marketing"
        )
        
        # Check user permissions
        can_manage = agency.can_user_manage(user)
        
        # Get agency statistics
        brand_count = agency.get_active_brands_count()
        campaign_count = agency.get_active_campaigns_count()
    ZstartupzStartup (1-10 employees)ZsmallzSmall (11-50 employees)mediumzMedium (51-200 employees)ZlargezLarge (201-1000 employees)Z
enterprisezEnterprise (1000+ employees)Ztv_advertisingzTV AdvertisingZdigital_marketingrg   Zcreative_serviceszCreative ServicesZmedia_planningzMedia PlanningZbrand_strategyzBrand StrategyZpublic_relationszPublic RelationsZsocial_mediazSocial MediaZcontent_creationzContent CreationZdata_analyticszData AnalyticsZfull_servicerf      zAgency NamezThe display name of the advertising agency as it appears to clients and in public listings. This should be the official business name or commonly used trading name.T)r   r   r   r   z
Legal Namez}The legal business name of the agency if different from the display name. Used for contracts, invoicing, and legal documents.)r   r   r   r   zagencies.AgencyTyperN   r   z|The type/category of this agency (e.g., Full Service, Digital, Creative). This helps in categorizing and filtering agencies.)	on_deleterelated_namer   r   r   r   zDetailed description of the agency and its services. This appears in agency profiles and helps clients understand what the agency offers. Include key services, specializations, and unique value propositions.r   Logoz}Agency logo image. Recommended size: 300x300 pixels or larger. Accepted formats: JPG, PNG, SVG, WebP. Maximum file size: 5MB.jpgjpegpngsvgwebp)allowed_extensions)	upload_tor   nullr   r   
validatorsWebsitezaAgency website URL including http:// or https://. This link will be displayed in agency profiles.)r   r   r   r      zPhone NumberzPrimary phone number including country code if international. Example formats: +1-555-123-4567, (555) 123-4567, +44 20 7123 4567zEmail AddresszuPrimary email address for the agency. This will be used for platform communications and displayed in agency profiles.)r   r   r   r   il  i  zFounded YearzlThe year the agency was founded. Used to calculate agency experience and for historical context in profiles.)r   r   r   r   r   r   zAgency SizeziSize category based on employee count. This helps clients understand the agency's capacity and structure.)r   choicesr   r   r   r   zEmployee CountzmExact number of employees in the agency. This provides more precise information than the size category alone.r   r   r   r   SpecializationszmList of agency specializations and service areas. Use this to highlight key competencies and expertise areas.r   r   r   r   FZVerifiedzWhether the agency has been verified by platform administrators. Verified agencies have enhanced credibility and may receive preferential placement in search results.r   ZFeaturedzWhether to feature this agency in listings and search results. Featured agencies receive enhanced visibility and premium placement.ActivezWhether the agency is currently active on the platform. Inactive agencies are hidden from public listings but data is preserved.2   UTCz	Time ZonezfPrimary time zone for the agency. Used for scheduling, campaign timing, and communication preferences.)r   r   r   r   rW   enZLanguagezmPrimary language preference using ISO 639-1 code (e.g., 'en' for English, 'es' for Spanish, 'fr' for French).Zowned_agenciesZOwnerzPrimary owner of the agency with full administrative rights. The owner can manage all aspects of the agency including team members, brands, and campaigns.c                   @   sb   e Zd ZedZedZdddgZdZej	dgdej	dgdej	dd	gdej	d
d	gdgZ
dS )zAgency.Metarx   ZAgenciesz-is_featuredz-is_verifiedr   )r    rp   is_verifiedrQ   rU   N)r$   r%   r&   r(   r   r)   r*   r+   r   r,   r.   r1   r1   r1   r2   r3     s   
r3   c                 C   s   | j S )z+Return string representation of the agency.r4   r5   r1   r1   r2   r7     s    zAgency.__str__c                 C   sh   g }| j r|| j  | jr(|| j | jr:|| j | jrL|| j | jr^|| j d|S )z
        Get the complete formatted address of the agency.
        
        Returns:
            str: Formatted address string
        z, )street_addressro   citystate_provincepostal_codecountryjoin)r6   address_partsr1   r1   r2   get_full_address  s    zAgency.get_full_addressc                 C   s$   | j rt| j S t| j| jdS )z
        Get a human-readable display of employee count.
        
        Returns:
            str: Employee count range or exact number
        Unknown)employee_countstrdictAGENCY_SIZE_CHOICESgetagency_sizer5   r1   r1   r2   get_employee_count_display1  s    
z!Agency.get_employee_count_displayc                 C   s   | j r| j jS dS )z)Check if the agency is of a premium type.F)rp   r   r5   r1   r1   r2   r   <  s    zAgency.is_premiumN)3r$   r%   r&   r'   r(   r   ZSPECIALIZATION_CHOICESr   rr   r   Z
legal_name
ForeignKeyPROTECTrp   rs   r?   
ImageFieldr   r   logoURLFieldr   websitephone
EmailFieldr   emailrt   r   r   Zfounded_yearr   r   	JSONFieldlistspecializationsru   r   rU   rQ   	time_zonelanguager   CASCADEownerr3   r7   r   r   propertyr   r1   r1   r1   r2   rx     sl  7





















rx   c                   @   sd  e Zd ZdZdedfdedfdedfded	fd
edfdedfdedfdedfdedfdedfdedfgZejeej	dededdZ
ejeejdddededd Zejd!eded"ed#d$Zejd%ed&ed'd(Zejded)ed*d(Zejdded+ed,d-Zejeded.ed/d0ZG d1d2 d2Zd3d4 Zed5d6 Zd7S )8AgencyTeamMembera  
    Model representing team members within agencies.
    
    This model tracks the team members of agencies, their roles,
    and contact information for client relationship management.
    
    Attributes:
        agency (Agency): The agency this person works for
        user (User): Associated user account (if any)
 
        position (str): Job title/position
        department (str): Department within the agency
  
        is_primary_contact (bool): Whether this is the primary contact
        is_public (bool): Whether to show in public listings
        linkedin_url (str): LinkedIn profile URL
        years_experience (int): Years of experience
        specializations (JSONField): Areas of expertise
    
managementZ
ManagementZaccountzAccount ManagementZcreativeZCreativeZstrategyZStrategymediaMedia
productionZ
ProductionZdigitalZDigitalZ	analyticsZ	AnalyticsfinanceFinancehrzHuman ResourcesotherOtherZteam_membersrx   z The agency this person works for)r{   r|   r   r   TZagency_membershipszUser Accountz Associated user account (if any))r{   r   r   r|   r   r   r   Z
DepartmentzDepartment within the agency)r   r   r   r   r   FzPrimary Contactz9Whether this person is the primary contact for the agency)r   r   r   zPublic Profilez5Whether to show this person in public agency listingszYears of Experiencez&Total years of professional experiencer   r   z%Areas of expertise and specializationr   c                   @   s*   e Zd ZedZedZdddgZdZdS )zAgencyTeamMember.MetazAgency Team MemberzAgency Team Membersz-is_primary_contactZuser__last_nameZuser__first_nameZagencies_team_memberN)r$   r%   r&   r(   r   r)   r*   r+   r1   r1   r1   r2   r3     s   
r3   c                 C   s   | j  d| j d| jj S )z0Return string representation of the team member. z - )
first_name	last_nameagencyr   r5   r1   r1   r2   r7     s    zAgencyTeamMember.__str__c                 C   s
   | j  S )z%Get the full name of the team member.)userget_full_namer5   r1   r1   r2   	full_name  s    zAgencyTeamMember.full_nameN)r$   r%   r&   r'   r(   ZDEPARTMENT_CHOICESr   r   rx   r   r   r   SET_NULLr   rr   Z
departmentru   Zis_primary_contactZ	is_publicrt   Zyears_experiencer   r   r   r3   r7   r   r   r1   r1   r1   r2   r   C  s|   










r   N)r'   	django.dbr   django.utils.translationr   r(   Zdjango.core.validatorsr   r   r   r   r   django.core.exceptionsr	   django.utilsr
   apps.accounts.modelsr   apps.common.modelsr   r   apps.agencies.utilsr   r   rx   r   r1   r1   r1   r2   <module>   s       ;  f