<?php

namespace app\controllers;

use Yii;
use yii\web\Controller;
use yii\web\NotFoundHttpException;
use yii\filters\AccessControl;
use yii\filters\VerbFilter;
use app\models\Tag;
use app\models\EntityTag;
use app\models\Course;
use app\models\CourseActivity;

class TagsController extends Controller
{
    public $layout = 'main';

    public function behaviors(): array
    {
        return [
            'access' => [
                'class' => AccessControl::class,
                'rules' => [[
                    'allow' => true,
                    'roles' => ['@'],
                ]],
            ],
            'verbs' => [
                'class'   => VerbFilter::class,
                'actions' => [
                    'delete' => ['post'],
                    'add'    => ['post'],
                    'remove' => ['post'],
                ],
            ],
        ];
    }

    // ================================================================
    // INDEX — tag list with usage counts
    // ================================================================
    public function actionIndex(): string
    {
        $tags = (new \yii\db\Query())
            ->select([
                't.*',
                'course_count'   => 'SUM(CASE WHEN et.entity_type = "course"   THEN 1 ELSE 0 END)',
                'activity_count' => 'SUM(CASE WHEN et.entity_type = "activity" THEN 1 ELSE 0 END)',
                'total_count'    => 'COUNT(et.id)',
            ])
            ->from(['t' => '{{%tag}}'])
            ->leftJoin(['et' => '{{%entity_tag}}'], 'et.tag_id = t.id')
            ->groupBy('t.id')
            ->orderBy('t.tag_name')
            ->all();

        return $this->render('index', ['tags' => $tags]);
    }

    // ================================================================
    // VIEW — all entities using this tag
    // ================================================================
    public function actionView(int $id): string
    {
        $tag = $this->findModel($id);

        $courseIds   = EntityTag::find()->select('entity_id')
            ->where(['entity_type' => EntityTag::TYPE_COURSE,   'tag_id' => $id])->column();
        $activityIds = EntityTag::find()->select('entity_id')
            ->where(['entity_type' => EntityTag::TYPE_ACTIVITY, 'tag_id' => $id])->column();

        $courses    = empty($courseIds)   ? [] : Course::find()->where(['id' => $courseIds])->orderBy(['course_code' => SORT_ASC])->all();
        $activities = empty($activityIds) ? [] : CourseActivity::find()->where(['id' => $activityIds])->with('course')->orderBy(['id' => SORT_ASC])->all();

        return $this->render('view', compact('tag', 'courses', 'activities'));
    }

    // ================================================================
    // CREATE
    // ================================================================
    public function actionCreate()
    {
        $model          = new Tag();
        $model->color   = Tag::nextColor();
        $model->is_active = 'Y';

        if ($model->load(Yii::$app->request->post())) {
            $model->tag_slug   = Tag::makeSlug($model->tag_name);
            $model->created_at = date('Y-m-d H:i:s');
            $model->updated_at = date('Y-m-d H:i:s');
            if ($model->save()) {
                Yii::$app->session->setFlash('success', "Tag '{$model->tag_name}' created.");
                return $this->redirect(['tags/index']);
            }
        }

        return $this->render('create', ['model' => $model]);
    }

    // ================================================================
    // UPDATE
    // ================================================================
    public function actionUpdate(int $id)
    {
        $model = $this->findModel($id);

        if ($model->load(Yii::$app->request->post())) {
            $model->tag_slug   = Tag::makeSlug($model->tag_name);
            $model->updated_at = date('Y-m-d H:i:s');
            if ($model->save(false)) {
                Yii::$app->session->setFlash('success', "Tag '{$model->tag_name}' updated.");
                return $this->redirect(['tags/index']);
            }
        }

        return $this->render('update', ['model' => $model]);
    }

    // ================================================================
    // DELETE — CASCADE removes all entity_tag rows via FK
    // ================================================================
    public function actionDelete(int $id)
    {
        $model = $this->findModel($id);
        $name  = $model->tag_name;
        $model->delete();
        Yii::$app->session->setFlash('success', "Tag '{$name}' deleted from all entities.");
        return $this->redirect(['tags/index']);
    }

    // ================================================================
    // ADD_TAG_TO_ENTITY
    //   POST: entity_type, entity_id, tag_name, return_url
    //   Finds or creates the tag by slug, then creates the association.
    // ================================================================
    public function actionAdd()
    {
        $post       = Yii::$app->request->post();
        $entityType = trim($post['entity_type'] ?? '');
        $entityId   = (int) ($post['entity_id']   ?? 0);
        $tagName    = trim($post['tag_name']       ?? '');
        $returnUrl  = $this->safeReturnUrl($post['return_url'] ?? '');

        // --- Validate inputs ---
        $errors = [];
        if (!in_array($entityType, [EntityTag::TYPE_COURSE, EntityTag::TYPE_ACTIVITY], true)) {
            $errors[] = "Invalid entity type '{$entityType}'.";
        }
        if ($entityId <= 0) {
            $errors[] = 'Invalid entity ID.';
        }
        if ($tagName === '') {
            $errors[] = 'Tag name cannot be empty.';
        } elseif (mb_strlen($tagName) > 100) {
            $errors[] = 'Tag name must be 100 characters or less.';
        }

        if (!empty($errors)) {
            Yii::$app->session->setFlash('error', implode(' ', $errors));
            return $this->redirect($returnUrl);
        }

        // --- Validate entity exists ---
        $entityExists = match ($entityType) {
            EntityTag::TYPE_COURSE   => Course::find()->where(['id' => $entityId])->exists(),
            EntityTag::TYPE_ACTIVITY => CourseActivity::find()->where(['id' => $entityId])->exists(),
            default => false,
        };

        if (!$entityExists) {
            Yii::$app->session->setFlash('error', "Entity {$entityType}#{$entityId} not found.");
            return $this->redirect($returnUrl);
        }

        // --- Find or create tag ---
        $slug = Tag::makeSlug($tagName);
        if ($slug === '') {
            Yii::$app->session->setFlash('error', 'Tag name produced an empty slug — use letters or numbers.');
            return $this->redirect($returnUrl);
        }

        $tag = Tag::find()->where(['tag_slug' => $slug])->one();
        if (!$tag) {
            $tag             = new Tag();
            $tag->tag_name   = $tagName;
            $tag->tag_slug   = $slug;
            $tag->color      = Tag::nextColor();
            $tag->is_active  = 'Y';
            $tag->created_at = date('Y-m-d H:i:s');
            $tag->updated_at = date('Y-m-d H:i:s');
            if (!$tag->save(false)) {
                Yii::$app->session->setFlash('error', 'Could not create tag: ' . implode(', ', $tag->getFirstErrors()));
                return $this->redirect($returnUrl);
            }
        }

        // --- Check for duplicate association ---
        $alreadyTagged = EntityTag::find()
            ->where(['entity_type' => $entityType, 'entity_id' => $entityId, 'tag_id' => $tag->id])
            ->exists();

        if ($alreadyTagged) {
            Yii::$app->session->setFlash('error', "Tag '{$tag->tag_name}' is already applied to this {$entityType}.");
            return $this->redirect($returnUrl);
        }

        // --- Create association (ADD_TAG_TO_ENTITY) ---
        $et              = new EntityTag();
        $et->entity_type = $entityType;
        $et->entity_id   = $entityId;
        $et->tag_id      = $tag->id;
        $et->created_at  = date('Y-m-d H:i:s');

        if ($et->save(false)) {
            Yii::$app->session->setFlash('success',
                "Tag '{$tag->tag_name}' added to {$entityType} #{$entityId}."
            );
        } else {
            Yii::$app->session->setFlash('error', 'Failed to save tag association.');
        }

        return $this->redirect($returnUrl);
    }

    // ================================================================
    // REMOVE — detach a tag from an entity
    //   POST: entity_type, entity_id, tag_id, return_url
    // ================================================================
    public function actionRemove()
    {
        $post       = Yii::$app->request->post();
        $entityType = $post['entity_type'] ?? '';
        $entityId   = (int) ($post['entity_id'] ?? 0);
        $tagId      = (int) ($post['tag_id']    ?? 0);
        $returnUrl  = $this->safeReturnUrl($post['return_url'] ?? '');

        $et = EntityTag::find()
            ->where(['entity_type' => $entityType, 'entity_id' => $entityId, 'tag_id' => $tagId])
            ->one();

        if ($et) {
            $tagName = $et->tag ? $et->tag->tag_name : "#{$tagId}";
            $et->delete();
            Yii::$app->session->setFlash('success', "Tag '{$tagName}' removed.");
        } else {
            Yii::$app->session->setFlash('error', 'Tag association not found.');
        }

        return $this->redirect($returnUrl);
    }

    // ================================================================
    // Helpers
    // ================================================================
    protected function findModel(int $id): Tag
    {
        $model = Tag::findOne($id);
        if ($model === null) {
            throw new NotFoundHttpException('Tag not found.');
        }
        return $model;
    }

    /**
     * Allow only relative URLs to prevent open-redirect attacks.
     */
    private function safeReturnUrl(string $url): array|string
    {
        if ($url !== '' && strpos($url, '//') === false && strpos($url, ':') === false) {
            return $url;
        }
        return ['courses/index'];
    }
}
