<?php

namespace Acms\Services\Form;

use Field;

/**
 * フォームの永続化（データベースアクセス）を抽象化するコントラクト。
 *
 * SQL・テーブル/カラム名・シーケンス、生レコード↔ドメインの変換、入力 Field↔保存カラムの変換は実装側に閉じる。
 */
interface RepositoryInterface
{
    /**
     * フォームをIDで取得し、構造化（ドメイン）配列で返す
     *
     * @param int $formId
     * @return array{id:int, bid:int, code:string, name:string, scope:string, log:'0'|'1', data:\Field}|null
     */
    public function findById(int $formId): ?array;

    /**
     * フォームをコードで取得し、構造化（ドメイン）配列で返す（ブログツリー・グローバルスコープ考慮）
     *
     * @param string $code
     * @param int $blogId
     * @return array{id:int, bid:int, code:string, name:string, scope:string, log:'0'|'1', data:\Field}|null
     */
    public function findByCodeInTree(string $code, int $blogId): ?array;

    /**
     * フォームをIDで取得し、生レコードを返す（エクスポートで原本をそのまま扱うため）
     *
     * @param int $formId
     * @return array<string, mixed>|null
     */
    public function findRawById(int $formId): ?array;

    /**
     * 指定コードのフォームがツリー/スコープ上に存在するかどうか
     *
     * @param string $code
     * @param int|null $excludeFormId 除外する form_id
     * @param string $scope 'local' | 'global'
     * @param int $blogId
     * @return bool
     */
    public function existsCodeInTree(string $code, ?int $excludeFormId, string $scope, int $blogId): bool;

    /**
     * 対象ブログ内で form_code に一致する form_id を取得する
     *
     * @param string $code
     * @param int $blogId
     * @return int|null
     */
    public function findIdByCodeInBlog(string $code, int $blogId): ?int;

    /**
     * 投稿ログに指定の宛先メールが存在するかどうか（照合用の正規表現化は実装側で行う）
     *
     * @param int $formId
     * @param string $mail
     * @param int $blogId
     * @return bool
     */
    public function existsMailInLog(int $formId, string $mail, int $blogId): bool;

    /**
     * フォームを新規作成し form_id を返す
     *
     * 引数 $form は入力 Field（編集画面の保存）または保存属性の連想配列（インポート等）のどちらも受け取れる。
     * Field の場合の保存カラムへの変換（form_data のシリアライズ含む）は実装側で行う。
     *
     * @param int $blogId
     * @param \Field|array{code?:string, name?:string, scope?:string, log?:'0'|'1', data?:string} $form
     * @return int
     */
    public function insert(int $blogId, Field|array $form): int;

    /**
     * フォームを更新する（form_id・form_current_serial は維持）
     *
     * 引数 $form は入力 Field または保存属性の連想配列のどちらも受け取れる。
     * 連想配列を渡した場合は、含まれるキーに対応するカラムだけを更新する（部分更新）。
     * 例えば `['data' => $serialized]` だけ渡せば form_data のみを上書きし、code/name/scope/log は変更しない。
     * Field を渡した場合は全カラム（code/name/scope/log/data）を更新する。
     *
     * @param int $formId
     * @param int $blogId
     * @param \Field|array{code?:string, name?:string, scope?:string, log?:'0'|'1', data?:string} $form
     * @return void
     */
    public function update(int $formId, int $blogId, Field|array $form): void;

    /**
     * フォームを複製し、新しい form_id を返す
     *
     * @param int $sourceFormId
     * @param int $blogId
     * @param string $codeSuffix form_code に付与するサフィックス（末尾に新ID も付与される）
     * @param string $nameSuffix form_name に付与するサフィックス
     * @return int
     */
    public function duplicate(int $sourceFormId, int $blogId, string $codeSuffix, string $nameSuffix): int;

    /**
     * フォーム本体と、それに紐づく投稿ログをまとめて削除する（フォーム集約の削除）
     *
     * form_id は主キーのためブログIDは指定不要。
     *
     * @param int $formId
     * @return void
     */
    public function delete(int $formId): void;

    /**
     * form_id シーケンスを最適化する
     *
     * @return void
     */
    public function optimizeSequence(): void;
}
