<?php
namespace Misuzu\Users\Assets;

use Misuzu\Imaging\Image;

class UserAvatarAsset extends UserImageAsset implements UserAssetScalableInterface {
    private const FORMAT = 'avatars/%s/%d.msz';
    private const DIR_ORIG = 'original';
    private const DIR_SIZE = '%1$dx%1$d';

    public const DEFAULT_DIMENSION = 200;
    public const DIMENSIONS = [
        40, 60, 80, 100, 120, 200, 240,
    ];

    private const MAX_RES  = 2000;
    private const MAX_BYTES  = 1000000;

    public function getMaxWidth(): int {
        global $cfg;
        return $cfg->getInteger('avatar.max_res', self::MAX_RES);
    }
    public function getMaxHeight(): int {
        return $this->getMaxWidth();
    }
    public function getMaxBytes(): int {
        global $cfg;
        return $cfg->getInteger('avatar.max_size', self::MAX_BYTES);
    }

    public static function clampDimensions(int $dimensions): int {
        $closest = null;
        foreach(self::DIMENSIONS as $dims)
            if($closest === null || abs($dimensions - $closest) >= abs($dims - $dimensions))
                $closest = $dims;
        return $closest;
    }

    public function getFileName(): string {
        return sprintf('avatar-%1$d.%2$s', $this->getUserId(), $this->getFileExtension());
    }
    public function getScaledFileName(int $dims): string {
        return sprintf('avatar-%1$d-%3$dx%3$d.%2$s', $this->getUserId(), $this->getScaledFileExtension($dims), self::clampDimensions($dims));
    }

    public function getScaledMimeType(int $dims): string {
        if(!$this->isScaledPresent($dims))
            return '';
        return mime_content_type($this->getScaledPath($dims));
    }
    public function getScaledFileExtension(int $dims): string {
        $imageSize = getimagesize($this->getScaledPath($dims));
        if($imageSize === false)
            return 'img';
        return self::TYPES_EXT[$imageSize[2]] ?? 'img';
    }

    public function getRelativePath(): string {
        return sprintf(self::FORMAT, self::DIR_ORIG, $this->getUserId());
    }
    public function getScaledRelativePath(int $dims): string {
        $dims = self::clampDimensions($dims);
        return sprintf(self::FORMAT, sprintf(self::DIR_SIZE, $dims), $this->getUserId());
    }

    public function getScaledPath(int $dims): string {
        return $this->getStoragePath() . DIRECTORY_SEPARATOR . $this->getScaledRelativePath($dims);
    }
    public function isScaledPresent(int $dims): bool {
        return is_file($this->getScaledPath($dims));
    }
    public function deleteScaled(int $dims): void {
        if($this->isScaledPresent($dims))
            unlink($this->getScaledPath($dims));
    }
    public function ensureScaledExists(int $dims): void {
        if(!$this->isPresent())
            return;
        $dims = self::clampDimensions($dims);

        if($this->isScaledPresent($dims))
            return;

        $scaledPath = $this->getScaledPath($dims);
        $scaledDir = dirname($scaledPath);
        if(!is_dir($scaledDir))
            mkdir($scaledDir, 0775, true);

        $scale = Image::create($this->getPath());
        $scale->squareCrop($dims);
        $scale->save($scaledPath);
        $scale->destroy();
    }

    public function getPublicScaledPath(int $dims): string {
        return self::PUBLIC_STORAGE . '/' . $this->getScaledRelativePath($dims);
    }

    public function delete(): void {
        parent::delete();
        foreach(self::DIMENSIONS as $dims)
            $this->deleteScaled($dims);
    }
}
