<?php

namespace pictpostpersonal\model;

use PDO;
use pictpostpersonal\Environment;
use pictpostpersonal\SQL;
use pictpostpersonal\SQLiteCRUD;
use pictpostpersonal\Utility;

/**
 * 記事に付帯するメディア情報を扱うクラス
 */
class Media
{
    private PDO $db;
    private SQLiteCRUD $sql_crud;
    private Setting $settings;

    public function __construct(PDO $db, Setting $settings)
    {
        $this->db = $db;
        $this->sql_crud = new SQLiteCRUD($db);
        $this->settings = $settings;
    }

    /**
     * メディア情報格納用のテーブルを生成する
     *
     * @return void
     */
    public static function initialize(SQLiteCRUD $sql_crud)
    {
        $sql_crud->table('media')->createTable(
            [
                SQL::Id('id'),
                SQL::DateTime('created_at'),
                SQL::Integer('article_id'),
                SQL::Integer('sort'),
                SQL::Text('file_name'),
                SQL::Text('sub_dir'),
                SQL::Integer('width'),
                SQL::Integer('height'),
                SQL::Text('thumb_l_name'),
                SQL::Integer('thumb_l_width'),
                SQL::Integer('thumb_l_height'),
                SQL::Text('thumb_name'),
                SQL::Integer('thumb_width'),
                SQL::Integer('thumb_height'),
                SQL::Text('type', 'image'),
                SQL::Text('comment', ''),
            ],
            [
                'article_id',
            ]
        );
    }

    /**
     * 指定されたIDのメディア情報を取得する
     *
     * @param int $mediaId メディアのID
     * @return array 画像の一覧。
     */
    public function getByMediaId($media_id): array
    {
        $conditions = ['id' => $media_id];
        $rows = $this->sql_crud
            ->table('media')
            ->orderBy('sort ASC')
            ->where('id = :id', $conditions)
            ->fetch();

        return $rows;
    }

    /**
     * 記事に付帯したメディアの一覧を取得する
     *
     * @param int    $articleId 対象記事のID
     * @param string $type      対象ファイルのメディアタイプ("image", "movie")。空文字の場合すべて。
     * @return array 画像の一覧。
     */
    public function getByArticleId($article_id, string $type = ''): array
    {
        $query = 'article_id = :article_id';
        $conditions = ['article_id' => $article_id];

        if ($type !== '') {
            $query .= ' AND type = :type';
            $conditions['type'] = $type;
        }

        $rows = $this->sql_crud
            ->table('media')
            ->orderBy('sort ASC')
            ->where($query, $conditions)
            ->fetch();

        return $rows;
    }

    /**
     * 指定されたファイル名のメディア情報を取得する
     *
     * @param string $fileName  ファイル名
     * @param string $type      対象ファイルのメディアタイプ("image", "movie")。空文字の場合すべて。
     * @return array 画像の一覧。
     */
    public function getByFileName(string $file_name, string $type = ''): array
    {
        $query = 'file_name = :file_name';
        $conditions = ['file_name' => $file_name];

        if ($type !== '') {
            $query .= ' AND type = :type';
            $conditions['type'] = $type;
        }

        $rows = $this->sql_crud
            ->table('media')
            ->orderBy('sort ASC')
            ->where($query, $conditions)
            ->fetch();

        return $rows;
    }

    /**
     * 記事に付帯したメディアの一覧のうち、最後のソート番号を取得する
     *
     * @param int $articleId 記事のID
     * @return int ソート番号
     */
    public function getLastSortNumber($article_id): int
    {
        $stmt = $this->db->prepare('SELECT MAX(sort) AS sort FROM media WHERE article_id = :article_id');
        $stmt->bindValue(':article_id', $article_id, PDO::PARAM_INT);
        $stmt->execute();
        $result = $stmt->fetch(PDO::FETCH_ASSOC);

        return $result && !empty($result['sort']) ? (int)$result['sort'] : 0;
    }

    /**
     * 新しいメディアを登録する
     *
     * @param int    $articleId     記事ID
     * @param string $type          メディアタイプ("image" or "movie")
     * @param string $fileName      ファイル名
     * @param string $subDir        サブディレクトリ
     * @param int    $width         幅
     * @param int    $height        高さ
     * @param string $thumbLName    大サムネイル名
     * @param int    $thumbLWidth   大サムネイル幅
     * @param int    $thumbLHeight  大サムネイル高さ
     * @param string $thumbName     小サムネイル名
     * @param int    $thumbWidth    小サムネイル幅
     * @param int    $thumbHeight   小サムネイル高さ
     * @param string $comment       コメント
     * @param int    $sort          ソート番号
     * @return int 登録されたメディアのID
     */
    public function add(
        int $article_id,
        string $type,
        string $file_name,
        string $sub_dir,
        int $width,
        int $height,
        string $thumb_lname,
        int $thumb_lwidth,
        int $thumb_lheight,
        string $thumb_name,
        int $thumb_width,
        int $thumb_height,
        string $comment,
        int $sort
    ): int {

        if (Environment::isDemoMode()) {
            $comment = htmlspecialchars(strip_tags($comment));
        }

        $data = [
            'created_at'       => Utility::getCurrentTime($this->settings->getValue('timezone', 'Asia/Tokyo')),
            'article_id'       => $article_id,
            'sort'             => $sort,
            'file_name'        => $file_name,
            'sub_dir'          => $sub_dir,
            'width'            => $width,
            'height'           => $height,
            'thumb_l_name'     => $thumb_lname,
            'thumb_l_width'    => $thumb_lwidth,
            'thumb_l_height'   => $thumb_lheight,
            'thumb_name'       => $thumb_name,
            'thumb_width'      => $thumb_width,
            'thumb_height'     => $thumb_height,
            'type'             => $type,
            'comment'          => $comment,
        ];

        $result_id = $this->sql_crud->table('media')->create($data);
        return $result_id;
    }

    /**
     * 並び替え番号、コメントを更新する
     *
     * @param int    $mediaId メディアID
     * @param int    $sort    ソート番号
     * @param string $comment コメント
     * @return void
     */
    public function updateInfoById($media_id, $sort, string $comment): void
    {
        if (Environment::isDemoMode()) {
            $comment = htmlspecialchars(strip_tags($comment));
        }
        $data = [
            'sort'    => $sort,
            'comment' => $comment,
        ];

        $this->sql_crud
            ->table('media')
            ->where('id = :id', ['id' => $media_id])
            ->update($data);
    }

    /**
     * ファイル名でソート番号を更新する
     *
     * @param string $fileName ファイル名
     * @param int    $sort     ソート番号
     * @return void
     */
    public function updateSortByFileName(string $file_name, $sort): void
    {
        $data = [
            'sort' => $sort,
        ];

        $this->sql_crud
            ->table('media')
            ->where('file_name = :file_name', ['file_name' => $file_name])
            ->update($data);
    }

    /**
     * 指定された記事IDに関連するメディアを削除する
     *
     * @param int $articleId 記事ID
     * @return void
     */
    public function deleteByArticleId($article_id): void
    {
        $stmt = $this->db->prepare('DELETE FROM media WHERE article_id = :article_id');
        $stmt->bindValue(':article_id', $article_id, PDO::PARAM_INT);
        $stmt->execute();
    }

    /**
     * 指定されたメディアIDのメディアを削除する
     *
     * @param int $mediaId メディアID
     * @return void
     */
    public function deleteByMediaId($media_id): void
    {
        $stmt = $this->db->prepare('DELETE FROM media WHERE id = :media_id');
        $stmt->bindValue(':media_id', $media_id, PDO::PARAM_INT);
        $stmt->execute();
    }

    /**
     * 指定されたファイル名のメディアを削除する
     *
     * @param string $fileName ファイル名
     * @return void
     */
    public function deleteByFileName(string $file_name): void
    {
        $stmt = $this->db->prepare('DELETE FROM media WHERE file_name = :file_name');
        $stmt->bindValue(':file_name', $file_name, PDO::PARAM_STR);
        $stmt->execute();
    }
}
