"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateContentTypeSchema = void 0;
const collation_type_1 = require("./collation-type");
const fs = require("fs-extra");
const common_1 = require("@nestjs/common");
const change_case_1 = require("change-case");
const generateContentTypeSchema = (contentTypesSchema) => {
    const rootFolder = process.env.INIT_CWD;
    try {
        fs.removeSync(`${rootFolder}/prisma/schemas/content-type-builder.prisma`);
    }
    catch (err) {
        console.warn(err);
    }
    fs.mkdirSync(`${rootFolder}/prisma/schemas`, {
        recursive: true,
    });
    let content = `
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
  binaryTargets = ["native"]
}  

`;
    Object.keys(contentTypesSchema).forEach((contentTypeId) => {
        content +=
            generateContentTypeSchemaContent(contentTypesSchema[contentTypeId], contentTypesSchema) + '\n';
    });
    fs.writeFileSync(`${rootFolder}/prisma/schemas/content-type-builder.prisma`, content, {
        encoding: 'utf-8',
    });
};
exports.generateContentTypeSchema = generateContentTypeSchema;
const generateContentTypeSchemaContent = (contentType, contentTypesSchema) => {
    let schemaAttribute = '';
    let enumTxt = '';
    Object.keys(contentType.attributes).forEach((attributeName, index) => {
        const attribute = contentType.attributes[attributeName];
        if (attribute.type === 'enumeration') {
            const attributeEnum = attribute;
            enumTxt += `\n
enum ${(0, change_case_1.pascalCase)(contentType.collectionName)}${(0, change_case_1.pascalCase)(attributeName)} {
  ${attributeEnum.enum.join('\n  ')}
}`;
        }
        if (index !== 0)
            schemaAttribute += '\n';
        let property = '';
        if (attribute.type === 'relation') {
            property = generateSchemeAttributeRelationType(attributeName, attribute, contentType.collectionName, contentTypesSchema);
        }
        else {
            property = `  ${attributeName} `;
            property +=
                ' ' +
                    generateSchemeAttributeType(attribute, attributeName, contentType.collectionName);
            property += '' + generateSchemeAttributeRequired(attribute.required);
            property += ' ' + generateSchemeAttributeNativeType(attribute);
        }
        schemaAttribute += property;
    });
    const schemaTemplate = `
${enumTxt}
model ${(0, change_case_1.pascalCase)(contentType.collectionName)} {
  id String @id @default(uuid()) @db.Uuid()
    
${schemaAttribute}
  ${contentType.options.draftAndPublish
        ? `\n  publishedAt          DateTime?                 @db.Timestamptz()
publishedById        String?                   @db.Uuid()
publishedBy          String?`
        : ''}
  createdAt          DateTime                  @default(now()) @db.Timestamptz()
  createdById        String?                   @db.Uuid()
  createdBy          String?
  updatedAt          DateTime                  @updatedAt @db.Timestamptz()
  updatedById        String?                   @db.Uuid()
  updatedBy          String?${contentType.options.softDelete
        ? `\n  deletedAt          DateTime?                 @db.Timestamptz()
deletedById        String?                   @db.Uuid()
deletedBy          String?`
        : ''}
}
`;
    return schemaTemplate;
};
const generateSchemeAttributeRelationType = (attributeName, attribute, modelName, contentTypesSchema) => {
    const attrRelation = attribute;
    const target = contentTypesSchema[attrRelation.target];
    if (!target) {
        throw new common_1.BadRequestException(`target: ${target} not found in schema`);
    }
    switch (attrRelation.relation) {
        case 'oneToOne':
            if (attrRelation.mappedBy) {
                return `${attributeName} ${(0, change_case_1.pascalCase)(target.collectionName)}${attrRelation.required ? '' : '?'}`;
            }
            return `${(0, change_case_1.camelCase)(target.collectionName)}Id String${attrRelation.required ? '' : '?'}  @unique @db.Uuid()
${attributeName}   ${(0, change_case_1.pascalCase)(target.collectionName)} @relation(fields: [${(0, change_case_1.camelCase)(target.collectionName)}Id], references: [id])`;
        case 'oneToMany':
            return `${attributeName} ${(0, change_case_1.pascalCase)(target.collectionName)}[]`;
        case 'manyToOne':
            return `${(0, change_case_1.camelCase)(target.collectionName)}Id        String${attrRelation.required ? '' : '?'}   @db.Uuid()
      ${attributeName} ${(0, change_case_1.pascalCase)(target.collectionName)}? @relation(fields: [${(0, change_case_1.camelCase)(target.collectionName)}Id], references: [id])`;
        case 'manyToMany':
            let relationName = '';
            if (modelName > target.collectionName) {
                relationName = `${(0, change_case_1.pascalCase)(modelName)}${(0, change_case_1.pascalCase)(target.collectionName)}Relation`;
            }
            else {
                relationName = `${(0, change_case_1.pascalCase)(target.collectionName)}${(0, change_case_1.pascalCase)(modelName)}Relation`;
            }
            return `${attributeName} pascalCase(
        target.collectionName,
      )}[] @relation("${relationName}")`;
    }
};
const generateSchemeAttributeType = (attribute, attributeName, modelName) => {
    switch (attribute.type) {
        case 'string':
        case 'password':
        case 'text':
        case 'richtext':
            return 'String';
        case 'integer':
            return 'Int';
        case 'bigint':
            return 'BigInt';
        case 'float':
            return 'Float';
        case 'decimal':
            return 'Decimal';
        case 'boolean':
            return 'Boolean';
        case 'json':
            return 'Json';
        case 'date':
        case 'datetime':
        case 'time':
            return 'DateTime';
        case 'enumeration':
            return `${(0, change_case_1.pascalCase)(modelName)}${(0, change_case_1.pascalCase)(attributeName)}`;
        case 'relation':
            return '';
        default:
            throw new common_1.BadRequestException(`Current attribute type ${attribute.type} is not supported`);
    }
};
const generateSchemeAttributeRequired = (required) => {
    if (required) {
        return '';
    }
    return '?';
};
const generateSchemeAttributeNativeType = (attribute) => {
    switch (attribute.type) {
        case 'string': {
            let txt = '@db.VarChar(255)';
            const attributeStr = attribute;
            if (attributeStr.maxLength) {
                txt = `@db.VarChar(${attributeStr.maxLength})`;
            }
            if (attributeStr.unique) {
                txt += ' @unique';
            }
            if (attributeStr.default) {
                txt += ` @default("${attributeStr.default}")`;
            }
            return txt;
        }
        case 'password':
            return '@db.VarChar(255)';
        case 'text':
        case 'richtext': {
            let txt = '@db.Text';
            const attributeStr = attribute;
            if (attributeStr.unique) {
                txt += ' @unique';
            }
            if (attributeStr.default) {
                txt += ` @default("${attributeStr.default}")`;
            }
            return txt;
        }
        case 'integer': {
            let txt = '';
            const attributeNumber = attribute;
            if (attributeNumber.unique) {
                txt += ' @unique';
            }
            if (attributeNumber.default) {
                txt += ` @default(${attributeNumber.default})`;
            }
            return txt;
        }
        case 'bigint': {
            let txt = '';
            const attributeNumber = attribute;
            if (attributeNumber.unique) {
                txt += ' @unique';
            }
            if (attributeNumber.default) {
                txt += ` @default(${attributeNumber.default})`;
            }
            return txt;
        }
        case 'float': {
            let txt = '';
            const attributeNumber = attribute;
            if (attributeNumber.unique) {
                txt += ' @unique';
            }
            if (attributeNumber.default) {
                txt += ` @default(${attributeNumber.default})`;
            }
            return txt;
        }
        case 'decimal': {
            const attributeDecimal = attribute;
            let txt = `@db.Decimal(${attributeDecimal.precision}, ${attributeDecimal.scale})`;
            if (attributeDecimal.unique) {
                txt += ' @unique';
            }
            if (attributeDecimal.default) {
                txt += ` @default(${attributeDecimal.default})`;
            }
            return txt;
        }
        case 'boolean': {
            let txt = '';
            const attributeBoolean = attribute;
            if (attributeBoolean.unique) {
                txt += ' @unique';
            }
            if (attributeBoolean.default) {
                txt += ` @default(${attributeBoolean.default})`;
            }
            return txt;
        }
        case 'json':
            return '@db.JsonB';
        case 'date': {
            let txt = '@db.Date';
            const attributeBoolean = attribute;
            if (attributeBoolean.unique) {
                txt += ' @unique';
            }
            if (attributeBoolean.default) {
                txt += ` @default(${attributeBoolean.default})`;
            }
            return txt;
        }
        case 'datetime': {
            let txt = '@db.Timestamp()';
            const attributeBoolean = attribute;
            if (attributeBoolean.unique) {
                txt += ' @unique';
            }
            if (attributeBoolean.default) {
                txt += ` @default(${attributeBoolean.default})`;
            }
            return txt;
        }
        case 'time': {
            let txt = '@db.Time()';
            const attributeBoolean = attribute;
            if (attributeBoolean.unique) {
                txt += ' @unique';
            }
            if (attributeBoolean.default) {
                txt += ` @default(${attributeBoolean.default})`;
            }
            return txt;
        }
        case 'enumeration':
            let txt = '';
            const attributeEnum = attribute;
            if (attributeEnum.unique) {
                txt += ' @unique';
            }
            if (attributeEnum.default) {
                txt += ` @default(${attributeEnum.default})`;
            }
            return txt;
        case 'relation':
            return '';
        default:
            throw new common_1.BadRequestException('Current attribute type is not supported');
    }
};
//# sourceMappingURL=generate-content-type-schema.js.map