<?php

namespace App\Util;

use App\Models\ProgramVideos;
use App\Models\VideoParts;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\DB;

class ProgramVideoUtil
{
    public static function fix_created_at_by_manual(ProgramVideos $base_video, int $each_time_sec, bool $force = false): bool
    {
        $base_time = $base_video->created_at->copy()
            ->subSeconds($base_video->start_sec)->subSeconds(($base_video->start_part - 1) * $each_time_sec);
        $query = ProgramVideos::query()
            ->where("video_bvid", "=", $base_video->video_bvid)
            ->where("id", "!=", $base_video->id);
        if (!$force) {
            $query->where(function (Builder $query) use ($base_video) {
                $query->where("created_at", ">", $base_video->created_at)->orWhere("created_at", "=", null);
            });
        }
        $program_videos = $query->get();
        DB::beginTransaction();
        try {
            /**
             * @var ProgramVideos $video
             */
            foreach ($program_videos as $video) {
                if ($video->id === $base_video->id) {
                    continue;
                }
                $video->created_at = static::calculate_program_time(
                    $base_time,
                    $video->start_sec,
                    ($video->start_part - 1) * $each_time_sec
                );
                $video->save();
            }
            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return false;
        }
    }

    public static function fix_created_at_by_part_info(string $bvid, bool $force = false): bool
    {
        $video_parts = VideoParts::query()->where("bvid", "=", $bvid)->get();
        if (sizeof($video_parts) === 0) {
            return false;
        }
        $query = ProgramVideos::query()->where("video_bvid", "=", $bvid);
        if (!$force) {
            $query->where("created_at", "=", null);
        }
        $program_videos = $query->get();
        DB::beginTransaction();
        try {
            /**
             * @var ProgramVideos $program_video
             */
            foreach ($program_videos as $program_video) {
                /**
                 * 计算开始时间
                 * @var VideoParts $cur_part
                 */
                $cur_part = $video_parts->where("part_num", "=", $program_video->start_part)->first();
                if ($cur_part) {
                    // 根据标题名称,判断开始时间
                    $title = $cur_part->title;
                    $date_str = substr($title, 0, 13);
                    $base_time = Carbon::createFromFormat("Ymd_Hi", $date_str);
                    $start_time = Carbon::createFromFormat("H:i:s", $program_video->start_time);
                    $program_video->created_at = static::calculate_program_time(
                        $base_time,
                        $start_time->secondsSinceMidnight()
                    );
                    if (!$program_video->stop_time) {
                        // 没有再去修复
                        if ($cur_part->duration->diffInMinutes($start_time) < 20) {
                            $program_video->stop_part = $cur_part->part_num + 1;
                            if ($program_video->stop_part > $video_parts->pluck("part_num")->max()) {
                                $program_video->stop_part = $video_parts->pluck("part_num")->max();
                            }
                        } else {
                            $program_video->stop_part = $cur_part->part_num;
                        }
                    }
                    $program_video->save();
                }
            }
            DB::commit();
            return true;
        } catch (\Exception $e) {
            DB::rollBack();
            return false;
        }
    }

    protected static function calculate_program_time(Carbon $base_time, int $seconds, int $bias = 0): Carbon
    {
        $time = $base_time->copy()->addSeconds($seconds)->addSeconds($bias);
        if ($time->second > 30) {
            $time->addMinute();
        }
        $time->seconds(0);
        return $time;
    }
}