<?php

namespace Phlaym\Roastmonday\DB;

use Psr\Log\LoggerInterface;

class DB extends BaseDB
{
    protected static $db_themes = 'thememonday';
    protected static $db_avatars = 'themeavatar';
    protected static $db_temp_avatars = 'tempavatar';

    protected $except_on_duplicate_entries = true;

    public function __construct(
        string $servername,
        string $db,
        string $username,
        string $password,
        $except_on_duplicate_entries = true,
        ?LoggerInterface $logger = null
    ) {
        parent::__construct($servername, $db, $username, $password, $logger);
        $this->except_on_duplicate_entries = $except_on_duplicate_entries;
        $this->logger->info("DB test");
    }

    public function listThemes()
    {
        $stmt = $this->conn->prepare(
            'SELECT * FROM `'
            . static::$db_themes
            . '` ORDER BY themedate DESC'
        );
        $stmt->execute();

        // set the resulting array to associative
        $stmt->setFetchMode(\PDO::FETCH_ASSOC);
        $themes = $stmt->fetchAll();
        $t = [];
        foreach ($themes as $theme) {
            $t[] = [
                'idx' => $theme['id'],
                'date' => new \DateTime($theme['themedate']),
                'tag' => $theme['themetag']
            ];
        }

        return $t;
    }

    public function getTheme($id)
    {
        $stmt = $this->conn->prepare(
            'SELECT * FROM `'
            . static::$db_themes
            . '` WHERE id = :id'
        );
        $stmt->bindParam(':id', $id);
        $stmt->execute();
        // set the resulting array to associative
        $stmt->setFetchMode(\PDO::FETCH_ASSOC);
        $theme = $stmt->fetch();
        return [
            'idx' => $theme['id'],
            'date' => new \DateTime($theme['themedate']),
            'tag' => $theme['themetag']
        ];
    }

    public function saveAvatar(
        $theme_id,
        $username,
        $user_realname,
        $post_id,
        $posttext,
        $postdate,
        $avatar,
        $overwrite_if_exist = false
    ) {
        $search = $this->conn->prepare(
            'SELECT COUNT(id) as pics FROM `'
            . static::$db_avatars
            . '` WHERE user_name LIKE :username AND thememonday = :theme'
        );
        $search->bindParam(':theme', $theme_id);
        $search->bindParam(':username', $username);

        $should_update = false;
        try {
            $search->execute();
            $search->setFetchMode(\PDO::FETCH_ASSOC);
            $p = $search->fetch();
            if ($p['pics'] != 0) {
                if ($overwrite_if_exist) {
                    $should_update = true;
                } else {
                    # Avatar already in DB
                    return static::$SKIPPED_DUPLICATE;
                }
            }
        } catch (\PDOException $Exception) {
            throw new DBException($Exception->getMessage());
        }

        if ($should_update) {
            $this->logger->info("Found existing avatar. Will overwrite", ['user' => $username, 'theme' => $theme_id]);
            $sql = $this->conn->prepare(
                'UPDATE `'
                . static::$db_avatars
                . '` SET postid = :postid, posttext = :posttext, postdate = :postdate, '
                . ' avatar_filename = :avatar'
                . ' WHERE user_name LIKE :username AND thememonday = :theme'
            );
        } else {
            $sql = $this->conn->prepare(
                'INSERT INTO `'
                . static::$db_avatars
                . '` (thememonday, user_name, postid, avatar_filename, posttext, user_realname, postdate)'
                . 'VALUES (:theme, :username, :postid, :avatar, :posttext, :user_realname, :postdate)'
            );
            $sql->bindParam(':user_realname', $user_realname);
        }


        $sql->bindParam(':theme', $theme_id);
        $sql->bindParam(':username', $username);
        $sql->bindParam(':postid', $post_id);
        $sql->bindParam(':posttext', $posttext);
        $sql->bindParam(':postdate', $postdate);
        $sql->bindParam(':avatar', $avatar);
        try {
            $sql->execute();
        } catch (\PDOException $Exception) {
            if (count($Exception->errorInfo) >= 2 && $Exception->errorInfo[1] === static::$ERR_DUPLICATE_ENTRY) {
                if ($this->except_on_duplicate_entries) {
                    throw new DuplicateEntryException();
                } else {
                    return static::$TRIED_INSERT_DUPLICATE;
                }
            } else {
                throw new DBException($Exception->getMessage());
            }
        }
        return static::$SUCCESS;
    }

    public function getAvatarsForTheme($id)
    {
        $stmt = $this->conn->prepare(
            'SELECT * FROM `'
            . static::$db_avatars
            . '` WHERE thememonday = :id'
        );
        $stmt->bindParam(':id', $id);
        $stmt->execute();
        $stmt->setFetchMode(\PDO::FETCH_ASSOC);
        $avatars = $stmt->fetchAll();
        $a = [];

        foreach ($avatars as $avatar) {
            $d = new \DateTime();
            $d->setTimestamp($avatar['postdate']);
            $a[] = [
                'file' => $avatar['avatar_filename'],
                'post_id' => $avatar['postid'],
                'posttext' => $avatar['posttext'],
                'postdate' => $d,
                'username' => $avatar['user_name'],
                'user_realname' => $avatar['user_realname'],
            ];
        }
        return $a;
    }

    public function addTheme($tag, $date)
    {
        $search = $this->conn->prepare(
            'SELECT id FROM`'
            . static::$db_themes
            . '` WHERE themedate LIKE :date AND themetag = :tag'
        );
        $search->bindParam(':date', $date);
        $search->bindParam(':tag', $tag);

        try {
            $search->execute();
            $search->setFetchMode(\PDO::FETCH_ASSOC);
            $p = $search->fetch();
            if ($p !== false) {
                return $p['id'];
            }
        } catch (\PDOException $Exception) {
            throw new DBException($Exception->getMessage());
        }

        $sql = $this->conn->prepare(
            'INSERT INTO `'
            . static::$db_themes
            . '` (themedate, themetag) VALUES (:date, :tag)'
        );
        $sql->bindParam(':date', $date);
        $sql->bindParam(':tag', $tag);
        try {
            $sql->execute();
        } catch (\PDOException $Exception) {
            if (count($Exception->errorInfo) >= 2 && $Exception->errorInfo[1] === DB::$ERR_DUPLICATE_ENTRY) {
                if ($this->except_on_duplicate_entries) {
                    throw new DuplicateEntryException();
                } else {
                    return $this->getIdForTag($tag);
                }
            } else {
                throw new DBException($Exception->getMessage());
            }
        }
        return $this->conn->lastInsertId();
    }

    public function getIdForTag($tag)
    {
        $stmt = $this->conn->prepare(
            'SELECT id FROM `'
            . static::$db_themes
            . '` WHERE themetag LIKE :tag'
        );
        $stmt->bindParam(':tag', $tag);
        $stmt->execute();
        // set the resulting array to associative
        $stmt->setFetchMode(\PDO::FETCH_ASSOC);
        $theme = $stmt->fetch();
        return $theme['id'];
    }

    public function addTempAvatar($user_id, $remove_at, $original_avatar, $auth_token)
    {
        # Delete old entries
        $sql = $this->conn->prepare(
            'DELETE FROM `'
                . static::$db_temp_avatars
                . '` WHERE user_id = :user_id'
        );
        $sql->bindParam(':user_id', $user_id);
        try {
            $sql->execute();
        } catch (\PDOException $Exception) {
            throw new DBException($Exception->getMessage());
        }
        # Add new entry
        $sql = $this->conn->prepare(
            'INSERT INTO `'
                . static::$db_temp_avatars
                . '` (user_id, remove_at, original_avatar, auth_token)'
                . 'VALUES (:user_id, FROM_UNIXTIME(:remove_at), :original_avatar, :auth_token)'
        );
        $sql->bindParam(':user_id', $user_id);
        $sql->bindParam(':remove_at', $remove_at);
        $sql->bindParam(':original_avatar', $original_avatar);
        $sql->bindParam(':auth_token', $auth_token);
        try {
            $sql->execute();
        } catch (\PDOException $Exception) {
            throw new DBException($Exception->getMessage());
        }
        return $this->conn->lastInsertId();
    }

    public function getOutdatedThemeAvatars()
    {
        $sql = 'SELECT * FROM `' . static::$db_temp_avatars . '` WHERE remove_at <= CURRENT_TIMESTAMP()';
        $stmt = $this->conn->prepare($sql);
        $stmt->execute();
        $res = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        return $res;
    }

    public function removeOutdatedThemeAvatars($user_id)
    {
        $sql = 'DELETE FROM `' . static::$db_temp_avatars . '` WHERE user_id = :user_id';
        $stmt = $this->conn->prepare($sql);
        $stmt->bindParam(':user_id', $user_id);
        $stmt->execute();
    }
}
