/*
 * Oak Video Editor - Non-Linear Video Editor
 * Copyright (C) 2025 Olive CE Team
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef FOOTAGE_H
#define FOOTAGE_H

#include <olive/core/core.h>
#include <QList>
#include <QDateTime>

#include "codec/decoder.h"
#include "footagedescription.h"
#include "node/output/viewer/viewer.h"
#include "render/cancelatom.h"
#include "render/videoparams.h"

namespace olive
{

/**
 * @brief A reference to an external media file with metadata in a project structure
 *
 * Footage objects serve two purposes: storing metadata about external media and storing it as a project item.
 * Footage objects store a list of Stream objects which store the majority of video/audio metadata. These streams
 * are identical to the stream data in the files.
 */
class Footage : public ViewerOutput {
	Q_OBJECT
public:
	/**
   * @brief Footage Constructor
   */
	Footage(const QString &filename = QString());

	NODE_DEFAULT_FUNCTIONS(Footage)

	virtual QString Name() const override
	{
		return tr("Media");
	}

	virtual QString id() const override
	{
		return QStringLiteral("org.olivevideoeditor.Olive.footage");
	}

	virtual QVector<CategoryID> Category() const override
	{
		return { kCategoryProject };
	}

	virtual QString Description() const override
	{
		return tr(
			"Import video, audio, or still image files into the composition.");
	}

	virtual void Retranslate() override;

	/**
   * @brief Reset Footage state ready for running through Probe() again
   *
   * If a Footage object needs to be re-probed (e.g. source file changes or Footage is linked to a new file), its
   * state needs to be reset so the Decoder::Probe() function can accurately mirror the source file. Clear() will
   * reset the Footage object's state to being freshly created (keeping the filename).
   *
   * In most cases, you'll be using olive::ProbeMedia() for re-probing which already runs Clear(), so you won't need
   * to worry about this.
   */
	void Clear();

	bool IsValid() const
	{
		return valid_;
	}

	/**
   * @brief Sets this footage to valid and ready to use
   */
	void SetValid();

	/**
   * @brief Return the current filename of this Footage object
   */
	QString filename() const;

	/**
   * @brief Set the filename
   *
   * NOTE: This does not automtaically clear the old streams and re-probe for new ones. If the file link has been
   * changed, this will need to be done manually.
   *
   * @param s
   *
   * New filename
   */
	void set_filename(const QString &s);

	/**
   * @brief Retrieve the last modified time/date
   *
   * The file's last modified timestamp is stored for potential organization in the ProjectExplorer. It can be
   * retrieved here.
   */
	const qint64 &timestamp() const;

	/**
   * @brief Set the last modified time/date
   *
   * This should probably only be done on import or replace.
   *
   * @param t
   *
   * New last modified time/date
   */
	void set_timestamp(const qint64 &t);

	void SetCancelPointer(CancelAtom *c)
	{
		cancelled_ = c;
	}

	int GetStreamIndex(Track::Type type, int index) const;
	int GetStreamIndex(const Track::Reference &ref) const
	{
		return GetStreamIndex(ref.type(), ref.index());
	}

	Track::Reference GetReferenceFromRealIndex(int real_index) const;

	/**
   * @brief Get the Decoder ID set when this Footage was probed
   *
   * @return
   *
   * A decoder ID
   */
	const QString &decoder() const;

	static QString DescribeVideoStream(const VideoParams &params);
	static QString DescribeAudioStream(const AudioParams &params);
	static QString DescribeSubtitleStream(const SubtitleParams &params);

	virtual void Value(const NodeValueRow &value, const NodeGlobals &globals,
					   NodeValueTable *table) const override;

	static QString GetStreamTypeName(Track::Type type);

	virtual Node *GetConnectedTextureOutput() override;

	virtual Node *GetConnectedSampleOutput() override;

	static rational AdjustTimeByLoopMode(rational time, LoopMode loop_mode,
										 const rational &length,
										 VideoParams::Type type,
										 const rational &timebase);

	virtual QVariant data(const DataType &d) const override;

	virtual int GetTotalStreamCount() const override
	{
		return total_stream_count_;
	}

	virtual bool LoadCustom(QXmlStreamReader *reader,
							SerializedData *data) override;
	virtual void SaveCustom(QXmlStreamWriter *writer) const override;

	static const QString kFilenameInput;

	virtual void AddedToGraphEvent(Project *p) override;
	virtual void RemovedFromGraphEvent(Project *p) override;

protected:
	virtual void InputValueChangedEvent(const QString &input,
										int element) override;

	virtual rational VerifyLengthInternal(Track::Type type) const override;

private:
	QString GetColorspaceToUse(const VideoParams &params) const;

	void Reprobe();

	VideoParams MergeVideoStream(const VideoParams &base,
								 const VideoParams &over);

	/**
   * @brief Internal timestamp object
   */
	qint64 timestamp_;

	/**
   * @brief Internal attached decoder ID
   */
	QString decoder_;

	bool valid_;

	CancelAtom *cancelled_;

	int total_stream_count_;

private slots:
	void CheckFootage();

	void DefaultColorSpaceChanged();
};

}

#endif // FOOTAGE_H
