<?php

declare(strict_types=1);

namespace backend\traits;

/**
 * AddressDataTrait provides virtual address properties for models.
 * 
 * This trait adds address-related properties and validation for models that
 * have address data stored in a related table but want to expose virtual
 * properties for form binding.
 * 
 * Usage:
 * ```php
 * class MyModel extends ActiveRecord
 * {
 *     use AddressDataTrait;
 * }
 * ```
 * 
 * @author Andrew Pickstock
 * @since 1.0
 */
trait AddressDataTrait
{
    /**
     * @var string|null Virtual property for address line 1 (not a DB column)
     */
    public ?string $address1 = null;
    
    /**
     * @var string|null Virtual property for address line 2 (not a DB column)
     */
    public ?string $address2 = null;
    
    /**
     * @var string|null Virtual property for address line 3 (not a DB column)
     */
    public ?string $address3 = null;
    
    /**
     * @var string|null Virtual property for town (not a DB column)
     */
    public ?string $town = null;
    
    /**
     * @var string|null Virtual property for county (not a DB column)
     */
    public ?string $county = null;
    
    /**
     * @var string|null Virtual property for country (not a DB column)
     */
    public ?string $country = null;
    
    /**
     * @var string|null Virtual property for postcode (not a DB column)
     */
    public ?string $postcode = null;
    
    /**
     * @var string|null Virtual property for telephone (not a DB column)
     */
    public ?string $telephone = null;
    
    /**
     * @var string|null Virtual property for fax (not a DB column)
     */
    public ?string $fax = null;
    
    /**
     * @var string|null Virtual property for contact name (not a DB column)
     */
    public ?string $contact = null;
    
    /**
     * Gets all address data as an associative array.
     * 
     * @return array<string, string|null> Address data
     */
    public function getAddressData(): array
    {
        return [
            'address1' => $this->address1,
            'address2' => $this->address2,
            'address3' => $this->address3,
            'town' => $this->town,
            'county' => $this->county,
            'country' => $this->country,
            'postcode' => $this->postcode,
            'telephone' => $this->telephone,
            'fax' => $this->fax,
            'contact' => $this->contact,
        ];
    }
    
    /**
     * Sets address data from an associative array.
     * 
     * @param array $data Address data
     * @return void
     */
    public function setAddressData(array $data): void
    {
        $this->address1 = $data['address1'] ?? $this->address1;
        $this->address2 = $data['address2'] ?? $this->address2;
        $this->address3 = $data['address3'] ?? $this->address3;
        $this->town = $data['town'] ?? $this->town;
        $this->county = $data['county'] ?? $this->county;
        $this->country = $data['country'] ?? $this->country;
        $this->postcode = $data['postcode'] ?? $this->postcode;
        $this->telephone = $data['telephone'] ?? $this->telephone;
        $this->fax = $data['fax'] ?? $this->fax;
        $this->contact = $data['contact'] ?? $this->contact;
    }
    
    /**
     * Checks if any address data has been set.
     * 
     * @return bool True if any address field has a value
     */
    public function hasAddressData(): bool
    {
        return !empty($this->address1)
            || !empty($this->address2)
            || !empty($this->address3)
            || !empty($this->town)
            || !empty($this->county)
            || !empty($this->country)
            || !empty($this->postcode)
            || !empty($this->telephone)
            || !empty($this->fax)
            || !empty($this->contact);
    }
    
    /**
     * Clears all address data.
     * 
     * @return void
     */
    public function clearAddressData(): void
    {
        $this->address1 = null;
        $this->address2 = null;
        $this->address3 = null;
        $this->town = null;
        $this->county = null;
        $this->country = null;
        $this->postcode = null;
        $this->telephone = null;
        $this->fax = null;
        $this->contact = null;
    }
    
    /**
     * Gets validation rules for address fields.
     * Merge these with your model's rules() method.
     * 
     * @return array Validation rules
     */
    public function getAddressRules(): array
    {
        return [
            [['address1', 'address2', 'address3', 'town', 'county', 'country', 'postcode', 'telephone', 'fax', 'contact'], 'string'],
            [['postcode'], 'string', 'max' => 20],
            [['telephone', 'fax'], 'string', 'max' => 30],
        ];
    }
    
    /**
     * Gets attribute labels for address fields.
     * Merge these with your model's attributeLabels() method.
     * 
     * @return array<string, string> Attribute labels
     */
    public function getAddressLabels(): array
    {
        return [
            'address1' => 'Address Line 1',
            'address2' => 'Address Line 2',
            'address3' => 'Address Line 3',
            'town' => 'Town/City',
            'county' => 'County/State',
            'country' => 'Country',
            'postcode' => 'Postcode/ZIP',
            'telephone' => 'Telephone',
            'fax' => 'Fax',
            'contact' => 'Contact Name',
        ];
    }
    
    /**
     * Formats the address as a single string.
     * 
     * @param string $separator Line separator (default: ', ')
     * @return string Formatted address
     */
    public function getFormattedAddress(string $separator = ', '): string
    {
        $parts = array_filter([
            $this->address1,
            $this->address2,
            $this->address3,
            $this->town,
            $this->county,
            $this->country,
            $this->postcode,
        ]);
        
        return implode($separator, $parts);
    }
}
