/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * The contents of this file are subject to the terms of the Liferay Enterprise
 * Subscription License ("License"). You may not use this file except in
 * compliance with the License. You can obtain a copy of the License by
 * contacting Liferay, Inc. See the License for the specific language governing
 * permissions and limitations under the License, including but not limited to
 * distribution rights of the Software.
 *
 *
 *
 */

package com.liferay.dynamic.data.mapping.internal.upgrade.v3_2_8;

import com.liferay.document.library.kernel.model.DLFileEntry;
import com.liferay.document.library.kernel.service.DLFileEntryLocalService;
import com.liferay.dynamic.data.mapping.io.DDMFormDeserializer;
import com.liferay.dynamic.data.mapping.io.DDMFormDeserializerDeserializeRequest;
import com.liferay.dynamic.data.mapping.io.DDMFormDeserializerDeserializeResponse;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesDeserializer;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesDeserializerDeserializeRequest;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesDeserializerDeserializeResponse;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesSerializer;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesSerializerSerializeRequest;
import com.liferay.dynamic.data.mapping.io.DDMFormValuesSerializerSerializeResponse;
import com.liferay.dynamic.data.mapping.model.DDMForm;
import com.liferay.dynamic.data.mapping.model.DDMFormField;
import com.liferay.dynamic.data.mapping.model.Value;
import com.liferay.dynamic.data.mapping.storage.DDMFormFieldValue;
import com.liferay.dynamic.data.mapping.storage.DDMFormValues;
import com.liferay.dynamic.data.mapping.util.DDMFormFieldValueTransformer;
import com.liferay.dynamic.data.mapping.util.DDMFormValuesTransformer;
import com.liferay.petra.string.StringBundler;
import com.liferay.portal.kernel.dao.jdbc.AutoBatchPreparedStatementUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.json.JSONFactory;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.upgrade.UpgradeProcess;
import com.liferay.portal.kernel.util.Validator;

import java.sql.PreparedStatement;
import java.sql.ResultSet;

import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author István András Dézsi
 */
public class UpgradeDDMFormDocumentLibraryFields extends UpgradeProcess {

	public UpgradeDDMFormDocumentLibraryFields(
		DDMFormDeserializer ddmFormDeserializer,
		DDMFormValuesDeserializer ddmFormValuesDeserializer,
		DDMFormValuesSerializer ddmFormValuesSerializer,
		DLFileEntryLocalService dlFileEntryLocalService,
		JSONFactory jsonFactory) {

		_ddmFormDeserializer = ddmFormDeserializer;
		_ddmFormValuesDeserializer = ddmFormValuesDeserializer;
		_ddmFormValuesSerializer = ddmFormValuesSerializer;
		_dlFileEntryLocalService = dlFileEntryLocalService;
		_jsonFactory = jsonFactory;
	}

	protected DDMForm deserialize(String content) {
		DDMFormDeserializerDeserializeRequest.Builder builder =
			DDMFormDeserializerDeserializeRequest.Builder.newBuilder(content);

		DDMFormDeserializerDeserializeResponse
			ddmFormDeserializerDeserializeResponse =
				_ddmFormDeserializer.deserialize(builder.build());

		return ddmFormDeserializerDeserializeResponse.getDDMForm();
	}

	protected DDMFormValues deserialize(String content, DDMForm ddmForm) {
		DDMFormValuesDeserializerDeserializeRequest.Builder builder =
			DDMFormValuesDeserializerDeserializeRequest.Builder.newBuilder(
				content, ddmForm);

		DDMFormValuesDeserializerDeserializeResponse
			ddmFormValuesDeserializerDeserializeResponse =
				_ddmFormValuesDeserializer.deserialize(builder.build());

		return ddmFormValuesDeserializerDeserializeResponse.getDDMFormValues();
	}

	@Override
	protected void doUpgrade() throws Exception {
		StringBundler sb = new StringBundler(8);

		sb.append("select DDMContent.contentId, DDMContent.data_, ");
		sb.append("DDMStructureVersion.structureVersionId, ");
		sb.append("DDMStructureVersion.definition from DDMContent inner join ");
		sb.append("DDMStorageLink on DDMContent.contentId = ");
		sb.append("DDMStorageLink.classPK inner join DDMStructureVersion on ");
		sb.append("DDMStorageLink.structureVersionId = ");
		sb.append("DDMStructureVersion.structureVersionId ");
		sb.append("where DDMStructureVersion.definition like '%ddm-documentlibrary%'");

		try (PreparedStatement ps1 = connection.prepareStatement(sb.toString());
			PreparedStatement ps2 =
				AutoBatchPreparedStatementUtil.concurrentAutoBatch(
					connection,
					"update DDMContent set data_ = ? where contentId = ?")) {

			try (ResultSet rs = ps1.executeQuery()) {
				while (rs.next()) {
					DDMForm ddmForm = deserialize(rs.getString("definition"));

					List<DDMFormField> ddmFormFields =
						ddmForm.getDDMFormFields();

					Stream<DDMFormField> stream = ddmFormFields.stream();

					List<DDMFormField> documentLibraryDDMFormFields =
						stream.filter(
							ddmFormField -> ddmFormField.getType(
							).equals(
								"ddm-documentlibrary"
							)
						).collect(
							Collectors.toList()
						);

					if (documentLibraryDDMFormFields.isEmpty()) {
						continue;
					}

					String data = rs.getString("data_");

					DDMFormValues ddmFormValues = deserialize(data, ddmForm);

					transformDocumentLibraryDDMFormFieldValues(ddmFormValues);

					ps2.setString(1, serialize(ddmFormValues));

					ps2.setLong(2, rs.getLong("contentId"));

					ps2.addBatch();
				}

				ps2.executeBatch();
			}
		}
	}

	protected String serialize(DDMFormValues ddmFormValues) {
		DDMFormValuesSerializerSerializeRequest.Builder builder =
			DDMFormValuesSerializerSerializeRequest.Builder.newBuilder(
				ddmFormValues);

		DDMFormValuesSerializerSerializeResponse
			ddmFormValuesSerializerSerializeResponse =
				_ddmFormValuesSerializer.serialize(builder.build());

		return ddmFormValuesSerializerSerializeResponse.getContent();
	}

	protected void transformDocumentLibraryDDMFormFieldValues(
			DDMFormValues ddmFormValues)
		throws Exception {

		DDMFormValuesTransformer ddmFormValuesTransformer =
			new DDMFormValuesTransformer(ddmFormValues);

		ddmFormValuesTransformer.addTransformer(
			new DocumentLibraryDDMFormFieldValueTransformer());

		ddmFormValuesTransformer.transform();
	}

	private final DDMFormDeserializer _ddmFormDeserializer;
	private final DDMFormValuesDeserializer _ddmFormValuesDeserializer;
	private final DDMFormValuesSerializer _ddmFormValuesSerializer;
	private final DLFileEntryLocalService _dlFileEntryLocalService;
	private final JSONFactory _jsonFactory;

	private class DocumentLibraryDDMFormFieldValueTransformer
		implements DDMFormFieldValueTransformer {

		@Override
		public String getFieldType() {
			return "ddm-documentlibrary";
		}

		@Override
		public void transform(DDMFormFieldValue ddmFormFieldValue)
			throws PortalException {

			Value value = ddmFormFieldValue.getValue();

			for (Locale locale : value.getAvailableLocales()) {
				String valueString = value.getString(locale);

				if (Validator.isNull(valueString)) {
					continue;
				}

				JSONObject jsonObject = _jsonFactory.createJSONObject(
					valueString);

				long groupId = jsonObject.getLong("groupId");
				String uuid = jsonObject.getString("uuid");

				DLFileEntry dlFileEntry =
					_dlFileEntryLocalService.fetchDLFileEntryByUuidAndGroupId(
						uuid, groupId);

				if (dlFileEntry == null) {
					continue;
				}

				jsonObject.put("title", dlFileEntry.getTitle());

				value.addString(locale, jsonObject.toString());
			}
		}

	}

}