<?php

namespace HelpGent\App\Repositories;

defined( 'ABSPATH' ) || exit;

use Exception;
use HelpGent\App\Models\ElementAnswers;
use HelpGent\App\Support\Element\Fields\Address;
use HelpGent\App\Support\Element\Fields\ContactInfo;
use HelpGent\App\Support\Element\Fields\DropDown;
use HelpGent\App\Support\Element\Fields\FileUpload;
use HelpGent\App\Support\Element\Fields\LiveChat;
use HelpGent\App\Support\Element\Fields\SingleSelect;
use HelpGent\App\Support\Element\Fields\YesNo;
use HelpGent\App\Support\Element\Fields\RatingStar;
use HelpGent\App\Utils\Repository;
use HelpGent\WpMVC\Database\Query\Builder;
use stdClass;

class AnswerRepository extends \HelpGent\WpMVC\Repositories\Repository {
    public ResponseRepository $response_repository;

    public FormRepository $form_repository;

    public AttachmentRepository $attachment_repository;

    protected array $elements = [];

    protected array $element_orders = [];

    public function get_query_builder(): Builder {
        return ElementAnswers::query();
    }

    public function __construct( ResponseRepository $response_repository, FormRepository $form_repository, AttachmentRepository $attachment_repository ) {
        $this->response_repository   = $response_repository;
        $this->form_repository       = $form_repository;
        $this->attachment_repository = $attachment_repository;
    }

    public function get( int $response_id ) {
        $response = $this->response_repository->get_by_id( $response_id );

        if ( ! $response ) {
            throw new Exception( esc_html__( 'Response not found.', 'helpgent' ), 404 );
        }

        /**
         * @var QuizRepository $quiz_repository
         */
        $quiz_repository = helpgent_singleton( QuizRepository::class );
        $contents        = $quiz_repository->get_response_form_content( $response_id );

        $elements = [];

        foreach ( $contents['elements'] ?? [] as $index => $element ) {
            if ( empty( $element['id'] ) ) {
                continue;
            }

            $elements[ $element['id'] ]            = $element;
            $this->element_orders[ $element['id'] ] = $index;
        }

        if ( empty( $elements ) ) {
            $form = $this->form_repository->get_by_id( $response->form_id );

            if ( ! $form ) {
                throw new Exception( esc_html__( 'Form not found.', 'helpgent' ), 404 );
            }

            $form     = helpgent_migrate_old_form( $form, false );
            $contents = $form->content;

            foreach ( $contents['elements'] ?? [] as $index => $element ) {
                if ( empty( $element['id'] ) ) {
                    continue;
                }

                $elements[ $element['id'] ]            = $element;
                $this->element_orders[ $element['id'] ] = $index;
            }
        }

        $this->elements = $elements;

        $answers = $this->get_query_builder()->with(
            [
                'attachment',
                'address',
                'contact_info',
                'open_ended_text_inners.attachment'
            ]
        )->select( 'id, element_id, element_type, value, attachment_id, points, created_at, updated_at' )->where( 'response_id', $response_id );

        $answers = array_values(
            array_filter(
                array_map(
                    function( $answer ) use ( $response_id ) {
                        return $this->prepare_answer( $answer, $response_id );
                    },
                    $answers->get()
                ),
                function( $answer ) {
                    return ! empty( $answer ) &&
                        ! in_array(
                            $answer->element_type,
                            [ LiveChat::get_key(), 'gdpr' ],
                            true
                        );
                }
            )
        );

        $answered_element_ids = array_map(
            function( $answer ) {
                return $answer->element_id;
            },
            $answers
        );

        if ( $quiz_repository->is_quiz_form( $contents ) ) {
            foreach ( $contents['elements'] ?? [] as $element ) {
                $element_id = $element['id'] ?? null;

                if (
                    empty( $element_id ) ||
                    ! $quiz_repository->is_quiz_element_type( $element['element_type'] ?? '' ) ||
                    in_array( $element_id, $answered_element_ids, true )
                ) {
                    continue;
                }

                $answers[] = $this->build_unanswered_quiz_answer(
                    $element,
                    $response_id
                );
            }
        }

        usort(
            $answers,
            function( $left, $right ) {
                $left_order  = $this->element_orders[ $left->element_id ] ?? PHP_INT_MAX;
                $right_order = $this->element_orders[ $right->element_id ] ?? PHP_INT_MAX;

                return $left_order <=> $right_order;
            }
        );

        return $answers;
    }

    protected function build_unanswered_quiz_answer( array $element, int $response_id ): ?stdClass {
        $answer               = new stdClass();
        $answer->id           = 'unanswered_' . ( $element['id'] ?? uniqid() );
        $answer->element_id   = $element['id'] ?? '';
        $answer->element_type = $element['element_type'] ?? '';
        $answer->value        = in_array(
            $answer->element_type,
            [ 'multi_select', 'picture_select' ],
            true
        )
            ? []
            : '';
        $answer->attachment   = null;
        $answer->attachment_id = null;
        $answer->created_at   = null;
        $answer->updated_at   = null;
        $answer->status       = 'publish';
        $answer->points       = 0;

        $answer = $this->prepare_answer( $answer, $response_id );

        if ( ! $answer ) {
            return null;
        }

        $answer->points         = 0;
        $answer->is_correct     = false;
        $answer->quiz_state     = 'incorrect';
        $answer->is_unanswered  = true;
        $answer->is_manual_grade = false;

        return $answer;
    }

    protected function get_fields_labels( array $element ): ?array {
        $fields = $element['fields'] ?? $element['attributes']['fields'] ?? null;

        if ( empty( $fields ) ) {
            return null;
        }

        return Repository::get_fields_labels( $fields );
    }

    protected function prepare_answer( $answer, int $response_id ) {
        if ( ! isset( $this->elements[$answer->element_id] ) ) {
            return null;
        }

        $answer->element = $this->elements[$answer->element_id];

        if ( empty( $this->elements[$answer->element_id]['attributes'] ) ) {
            return $answer;
        }

        $attributes = $this->elements[$answer->element_id]['attributes'];

        switch ( $answer->element_type ) {
            case RatingStar::get_key():
                $answer->rating_icon   = $attributes['rating_icon'];
                $answer->rating_amount = $attributes['rating_amount'];
                break;
            case FileUpload::get_key():
                $this->prepare_files_answers( $answer );
                break;
            case Address::get_key():
            case ContactInfo::get_key():
                $answer->labels = $this->get_fields_labels( $this->elements[$answer->element_id] );
                break;
            case SingleSelect::get_key():
            case DropDown::get_key():
            case YesNo::get_key():
                $answer->options = $attributes['options'];
                break;
            case 'open_ended_text':
                $answer->labels = Repository::get_fields_labels( $attributes['text_fields'] );
                break;
            default:
                break;
        }

        $answer = apply_filters( "helpgent_prepare_answer", $answer, $this->elements[$answer->element_id] );

        /**
         * @var QuizRepository $quiz_repository
         */
        $quiz_repository = helpgent_singleton( QuizRepository::class );
        $answer          = $quiz_repository->augment_answer( $answer, $this->elements[$answer->element_id], $response_id );

        if ( ! empty( $answer->attachment ) ) {
            Repository::bind_file_url( $answer->attachment );
        } elseif ( ! empty( $answer->open_ended_text_inners->attachment ) ) {
            Repository::bind_file_url( $answer->open_ended_text_inners->attachment );
        }

        $answer->element_title = isset( $attributes['title'] ) ? $attributes['title'] : esc_html__( 'Unknown', 'helpgent' );

        return $answer;
    }

    protected function prepare_files_answers( $answer ) {
        $file_ids = json_decode( $answer->value );

        if ( empty( $file_ids ) ) {
            $answer->attachments = [];
            return;
        }

        $files = Repository::attachment_query()->where_in( 'id', $file_ids )->get();
        $files = array_map(
            function( $file ) {
                return Repository::clean_file( Repository::bind_file_url( $file ) );
            }, $files
        );

        unset( $answer->value );

        $answer->attachments = $files;
    }
}
