# encoding: utf8

import os
import datetime
import logging
import numpy as np
import pandas as pd
import tensorflow as tf
import tensorflow_addons as tfa
from tensorflow.keras.initializers import Constant

from senti_analysis import config
from senti_analysis import constants
from senti_analysis.preprocess import load_embedding_matrix


def fc_nn(hidden, name=None):
    """
    Fully connected layer.
    :param hidden: share hidden layer
    :param name: output layer name
    :return: outputs
    """
    hidden = tf.keras.layers.Dense(64, activation='relu')(hidden)
    hidden = tf.keras.layers.Dense(32, activation='relu')(hidden)
    hidden = tf.keras.layers.Dense(16, activation='relu')(hidden)
    outputs = tf.keras.layers.Dense(4, activation='softmax', name=name)(hidden)

    return outputs


def get_model(learning_rate=config.LEARNING_RATE, name='model_v4'):
    """
    create model.
    :return: model
    """
    num_class = 4
    kernel_size = 5
    filters = 64
    pool_size = 4
    embedding_matrix = load_embedding_matrix()

    inputs = tf.keras.layers.Input(shape=(config.MAX_SEQUENCE_LENGTH,), name='input')
    embedding = tf.keras.layers.Embedding(embedding_matrix.shape[0], embedding_matrix.shape[1],
                                          embeddings_initializer=Constant(embedding_matrix),
                                          input_length=config.MAX_SEQUENCE_LENGTH,
                                          trainable=True)(inputs)
    share_hidden = tf.keras.layers.Conv1D(filters, kernel_size, padding='valid',
                                          activation='relu', strides=1)(embedding)
    share_hidden = tf.keras.layers.MaxPooling1D(pool_size=pool_size)(share_hidden)
    share_hidden = tf.keras.layers.GRU(256, activation='relu', return_sequences=True, reset_after=True)(share_hidden)
    share_hidden = tf.keras.layers.GRU(128, activation='relu', reset_after=True)(share_hidden)

    outputs = []
    for col in constants.COLS:
        outputs.append(fc_nn(share_hidden, name=col))

    model = tf.keras.Model(inputs=inputs, outputs=outputs, name=name)

    model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=learning_rate),
                  loss='sparse_categorical_crossentropy',
                  metrics=[tf.keras.metrics.SparseCategoricalAccuracy(name='acc'),
                           tfa.metrics.F1Score(num_class, average='micro')],)

    return model

tensorflow.keras.initializers.Constant tensorflow.keras.layers.Dense tensorflow.keras.layers.Conv1D tensorflow.keras.layers.MaxPooling1D tensorflow.keras.Model tensorflow.keras.layers.GRU tensorflow.keras.optimizers.Adam tensorflow.keras.metrics.SparseCategoricalAccuracy tensorflow.keras.layers.Input
[(41, 'senti_analysis.preprocess.load_embedding_matrix', 'load_embedding_matrix', ([], {}), False, 'from senti_analysis.preprocess import load_embedding_matrix\n'), (43, 'tensorflow.keras.layers.Input', 'tf.keras.layers.Input', ([], {'shape': '(config.MAX_SEQUENCE_LENGTH,)', 'name': '"""input"""'}), True, 'import tensorflow as tf\n'), (58, 'tensorflow.keras.Model', 'tf.keras.Model', ([], {'inputs': 'inputs', 'outputs': 'outputs', 'name': 'name'}), True, 'import tensorflow as tf\n'), (24, 'tensorflow.keras.layers.Dense', 'tf.keras.layers.Dense', (['(64)'], {'activation': '"""relu"""'}), True, 'import tensorflow as tf\n'), (25, 'tensorflow.keras.layers.Dense', 'tf.keras.layers.Dense', (['(32)'], {'activation': '"""relu"""'}), True, 'import tensorflow as tf\n'), (26, 'tensorflow.keras.layers.Dense', 'tf.keras.layers.Dense', (['(16)'], {'activation': '"""relu"""'}), True, 'import tensorflow as tf\n'), (27, 'tensorflow.keras.layers.Dense', 'tf.keras.layers.Dense', (['(4)'], {'activation': '"""softmax"""', 'name': 'name'}), True, 'import tensorflow as tf\n'), (48, 'tensorflow.keras.layers.Conv1D', 'tf.keras.layers.Conv1D', (['filters', 'kernel_size'], {'padding': '"""valid"""', 'activation': '"""relu"""', 'strides': '(1)'}), True, 'import tensorflow as tf\n'), (50, 'tensorflow.keras.layers.MaxPooling1D', 'tf.keras.layers.MaxPooling1D', ([], {'pool_size': 'pool_size'}), True, 'import tensorflow as tf\n'), (51, 'tensorflow.keras.layers.GRU', 'tf.keras.layers.GRU', (['(256)'], {'activation': '"""relu"""', 'return_sequences': '(True)', 'reset_after': '(True)'}), True, 'import tensorflow as tf\n'), (52, 'tensorflow.keras.layers.GRU', 'tf.keras.layers.GRU', (['(128)'], {'activation': '"""relu"""', 'reset_after': '(True)'}), True, 'import tensorflow as tf\n'), (60, 'tensorflow.keras.optimizers.Adam', 'tf.keras.optimizers.Adam', ([], {'learning_rate': 'learning_rate'}), True, 'import tensorflow as tf\n'), (45, 'tensorflow.keras.initializers.Constant', 'Constant', (['embedding_matrix'], {}), False, 'from tensorflow.keras.initializers import Constant\n'), (62, 'tensorflow.keras.metrics.SparseCategoricalAccuracy', 'tf.keras.metrics.SparseCategoricalAccuracy', ([], {'name': '"""acc"""'}), True, 'import tensorflow as tf\n'), (63, 'tensorflow_addons.metrics.F1Score', 'tfa.metrics.F1Score', (['num_class'], {'average': '"""micro"""'}), True, 'import tensorflow_addons as tfa\n')]