<?php

namespace _121Digital\Connect\Network\Models;

use InvalidArgumentException;

class NewSiteDTO
{
    public string $siteName;

    public string $domain;

    public string $path;

    public string $adminEmail;

    public function __construct(
        ?string $siteName = null,
        ?string $domain = null,
        ?string $path = null,
        ?string $adminEmail = null
    ) {
        if ($siteName !== null) {
            $this->validateAndSetSiteName($siteName);
        }
        if ($domain !== null) {
            $this->validateAndSetDomain($domain);
        }
        if ($path !== null) {
            $this->validateAndSetPath($path);
        }
        if ($adminEmail !== null) {
            $this->validateAndSetAdminEmail($adminEmail);
        }
    }

    // Factory methods for common creation scenarios
    public static function fromArray(array $data): self
    {
        $dto = new self();

        if (isset($data['site_name']) || isset($data['siteName'])) {
            $dto->setSiteName($data['site_name'] ?? $data['siteName']);
        }
        if (isset($data['domain'])) {
            $dto->setDomain($data['domain']);
        }
        if (isset($data['path'])) {
            $dto->setPath($data['path']);
        } else {
            $dto->setPath('/'); // Default path for new sites
        }
        if (isset($data['admin_email']) || isset($data['adminEmail'])) {
            $dto->setAdminEmail($data['admin_email'] ?? $data['adminEmail']);
        }

        return $dto;
    }

    public static function create(string $siteName, string $domain, string $adminEmail, string $path = '/'): self
    {
        return new self(
            siteName: $siteName,
            domain: $domain,
            path: $path,
            adminEmail: $adminEmail
        );
    }

    // Getters
    public function getSiteName(): string
    {
        return $this->siteName;
    }

    public function getDomain(): string
    {
        return $this->domain;
    }

    public function getPath(): string
    {
        return $this->path;
    }

    public function getAdminEmail(): string
    {
        return $this->adminEmail;
    }

    // Setters with validation
    public function setSiteName(string $siteName): void
    {
        $this->validateAndSetSiteName($siteName);
    }

    public function setDomain(string $domain): void
    {
        $this->validateAndSetDomain($domain);
    }

    public function setPath(string $path): void
    {
        $this->validateAndSetPath($path);
    }

    public function setAdminEmail(string $adminEmail): void
    {
        $this->validateAndSetAdminEmail($adminEmail);
    }

    // Validation methods
    public function isValid(): bool
    {
        return isset($this->siteName) &&
               isset($this->domain) &&
               isset($this->path) &&
               isset($this->adminEmail);
    }

    public function validate(): void
    {
        if (!isset($this->siteName)) {
            throw new InvalidArgumentException('Site name is required');
        }
        if (!isset($this->domain)) {
            throw new InvalidArgumentException('Domain is required');
        }
        if (!isset($this->path)) {
            throw new InvalidArgumentException('Path is required');
        }
        if (!isset($this->adminEmail)) {
            throw new InvalidArgumentException('Admin email is required');
        }
    }

    public function toArray(): array
    {
        return [
          'site_name' => $this->siteName ?? null,
          'domain' => $this->domain ?? null,
          'path' => $this->path ?? null,
          'admin_email' => $this->adminEmail ?? null,
        ];
    }

    // Convert to full SiteDTO once site is created with an ID
    public function toSiteDTO(int $siteId): SiteDTO
    {
        return SiteDTO::create(
            siteId: $siteId,
            siteName: $this->siteName,
            domain: $this->domain,
            path: $this->path,
            adminEmail: $this->adminEmail
        );
    }

    // Private validation methods
    private function validateAndSetSiteName(string $siteName): void
    {
        $trimmedName = trim($siteName);
        if (empty($trimmedName)) {
            throw new InvalidArgumentException('Site name cannot be empty');
        }
        if (strlen($trimmedName) > 255) {
            throw new InvalidArgumentException('Site name cannot exceed 255 characters');
        }
        $this->siteName = $trimmedName;
    }

    private function validateAndSetDomain(string $domain): void
    {
        $trimmedDomain = trim($domain);
        if (empty($trimmedDomain)) {
            throw new InvalidArgumentException('Domain cannot be empty');
        }

        // Basic domain validation
        // if (!preg_match('/^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/', $trimmedDomain)) {
        //   throw new InvalidArgumentException('Invalid domain format');
        // }

        if (strlen($trimmedDomain) > 253) {
            throw new InvalidArgumentException('Domain cannot exceed 253 characters');
        }

        $this->domain = strtolower($trimmedDomain);
    }

    private function validateAndSetPath(string $path): void
    {
        $trimmedPath = trim($path);
        if (empty($trimmedPath)) {
            $trimmedPath = '/';
        }

        // Ensure path starts with /
        if (!str_starts_with($trimmedPath, '/')) {
            $trimmedPath = '/' . $trimmedPath;
        }

        // Basic path validation - no invalid characters
        if (preg_match('/[<>"|?*]/', $trimmedPath)) {
            throw new InvalidArgumentException('Path contains invalid characters');
        }

        if (strlen($trimmedPath) > 500) {
            throw new InvalidArgumentException('Path cannot exceed 500 characters');
        }

        $this->path = $trimmedPath;
    }

    private function validateAndSetAdminEmail(string $adminEmail): void
    {
        $trimmedEmail = trim($adminEmail);
        if (empty($trimmedEmail)) {
            throw new InvalidArgumentException('Admin email cannot be empty');
        }

        if (!filter_var($trimmedEmail, \FILTER_VALIDATE_EMAIL)) {
            throw new InvalidArgumentException('Invalid email format');
        }

        if (strlen($trimmedEmail) > 320) {
            throw new InvalidArgumentException('Email cannot exceed 320 characters');
        }

        $this->adminEmail = strtolower($trimmedEmail);
    }
}
