defmodule Schemas.Clip.Channel do
  @moduledoc """
  Youtube etc. channel
  """
  alias Db.Repo
  alias Schemas.Clip.Video

  import Ecto.Changeset

  use Ecto.Schema

  @type t :: %__MODULE__{
          url: String.t(),
          username: String.t(),
          id: term(),
          videos: Ecto.Schema.has_many(Video.t())
        }

  @schema_prefix "clip"
  schema "channels" do
    # unique
    field(:url, :string)
    field(:username, :string)

    has_many(:videos, Video)
  end

  @yt_regex ~r/^https:\/\/www\.youtube\.com\/@([a-z0-9_-]+)$/

  def canon?(url) do
    url =~ @yt_regex
  end

  def url_to_username(url) do
    with [_, username] <- Regex.run(@yt_regex, url) do
      username
    end
  end

  def changeset(channel, params) do
    channel
    |> change(params)
    |> validate_required([:url, :username])
    |> validate_format(:url, @yt_regex)
    |> validate_format(:username, ~r/^[[:lower:]\-0-9_]+$/)
    |> unique_constraint([:url, :username], key: :duplicate)
  end

  import Ecto.Query

  def upsert_uploader_url!(url, username) do
    url = String.downcase(url, :ascii)
    username = String.downcase(username, :ascii)

    case Repo.one(from(c in __MODULE__, where: c.url == ^url)) do
      nil -> %__MODULE__{}
      # username may change, but w/e
      %__MODULE__{url: ^url, username: ^username} = chn -> chn
    end
    |> Ecto.Changeset.change(url: url, username: username)
    |> Repo.insert_or_update!()
  end
end
