public without sharing class MetaDataUtility {
    public static List<Metadata.LayoutSection> GetRecordTypePageLayout(string record_type_id, string objectType) {
        Map<string, object> mso = null;
        System.debug('rerord 6' + record_type_id + ':' + objectType);
        string layout_name = GetRecordTypePageLayoutName(record_type_id, objectType, UserInfo.getProfileId());
        System.debug('layout 8' + layout_name);

        List<Metadata.LayoutSection> temp = GetLayoutSections(objectType, layout_name);
        List<Metadata.LayoutSection> layoutSectionList = new List<Metadata.LayoutSection>();
        for (Metadata.LayoutSection section : temp) {
            boolean a = false;
            for (Metadata.LayoutColumn c : section.layoutColumns) {
                //system.debug(c);
                if (c.layoutItems != null && c.layoutItems.size() > 0) {
                    a = true;
                }
            }
            if (a) {
                layoutSectionList.add(section);
            }
        }
        return layoutSectionList;
    }

    /*[{
            "attributes": {  
                "type": "Layout",
                "url": "/services/data/v53.0/tooling/sobjects/Layout/00h10000009iAb5AAE"
            },
            "Id": "00h10000009iAb5AAE",
            "Name": ".客户人员レイアウト",
            "TableEnumOrId": "01I10000000er3hEAA",
            "LayoutType": "Standard"
        }]
     */

    public static string GetTableOrEnumId(string objectType) {
        Map<string, object> mso = null;
        string resp = null;
        string table_or_enum_id = objectType;
        if (objectType.endsWith('__c')) {
            resp = ToolingQuery('SELECT id,DeveloperName from CustomObject where DeveloperName =\'' + objectType.replace('__c', '') + '\'');
            if (resp == null) {
                system.debug('resp is not ok');
                return null;
            } else {
                mso = (Map<string, object>) Json.deserializeUntyped(resp);
                if (integer.valueOf(mso.get('size')) > 0) {
                    table_or_enum_id = string.valueOf(((Map<string, object>) (((List<object>) mso.get('records'))[0])).get('Id'));
                } else {
                    system.debug('no records');
                    return null;
                }
            }
        }
        System.debug('mso 60' + mso);

        return table_or_enum_id;
    }

    public static List<object> GetAllPageLayout(string objectType) {
        string resp = null;
        Map<string, object> mso = null;

        string table_or_enum_id = GetTableOrEnumId(objectType);

        if (string.isBlank(table_or_enum_id)) {
            return new List<object>();
        }

        resp = ToolingQuery('SELECT id,name,TableEnumOrId,LayoutType  FROM Layout where TableEnumOrId = \'' + table_or_enum_id + '\'');
        if (resp == null) {
            system.debug('Layout where TableEnumOrId=' + table_or_enum_id + ' is null');
            return null;
        } else {
            mso = (Map<string, object>) Json.deserializeUntyped(resp);
            if (integer.valueOf(mso.get('size')) > 0) {
                return (List<object>) mso.get('records');
            } else {
                system.debug('no records');
                return new List<object>();
            }
        }
    }

    public static string GetRecordTypePageLayoutName(string record_type_id, string objectType, string profile_id) {
        System.debug('objectType 92' + objectType);
        System.debug('profile 93 ' + profile_id);

        if (!string.isBlank(objectType)) {
            List<sobject> lso = [
                SELECT Id, Name, DeveloperName, SobjectType, IsActive, Description, BusinessProcessId
                FROM RecordType
                WHERE SobjectType = :objectType
            ];
            if (lso.size() == 0) {
                return string.valueOf(((Map<string, object>) (GetAllPageLayout(objectType)[0])).get('Name'));
            }
        }

        // 01210000000QfWdAAK
        string query = 'SELECT Layout.Name, Layout.TableEnumOrId, ProfileId, Profile.Name, RecordTypeId FROM ProfileLayout where id!=null ';
        if (!string.isBlank(record_type_id)) {
            query += ' and RecordTypeId = \'' + record_type_id + '\'';
        }

        if (!string.isBlank(objectType)) {
            query += ' and TableEnumOrId = \'' + GetTableOrEnumId(objectType) + '\'';
        }

        if (!string.isBlank(profile_id)) {
            query += ' and ProfileId = \'' + profile_id + '\'';
        }
        query += ' order by LastModifiedDate desc ';
        system.debug('query=' + query);
        string s = ToolingQuery(query);
        if (string.isBlank(s)) {
            system.debug('s is blank');
            return null;
        } else {
            Map<string, object> mso = (Map<string, object>) JSON.deserializeUntyped(s);
            System.debug('mso 122' + mso);

            if (integer.valueOf(mso.get('size')) > 0) {
                List<object> records = ((List<object>) mso.get('records'));

                mso = (Map<string, object>) (records[0]);
                return string.valueOf(((Map<string, object>) (mso.get('Layout'))).get('Name'));
            } else {
                return null;
            }
        }
    }

    public static string ToolingQuery(string query) {
        system.debug('query=' + query);
        String baseURL = 'callout:SF_Rest_API/services/data/v41.0/tooling/query?q=' + query.replace(' ', '+');
        HttpResponse resp = null;
        HttpRequest req = new HttpRequest();
        req.setMethod('GET');

        //req.setHeader('Authorization', 'Bearer ' + UserInfo.getsessionid());
        //req.setEndpoint(baseURL);
        req.setEndpoint(baseURL);

        Http client = new Http();
        resp = client.send(req);

        system.debug(resp.getStatus());
        system.debug(resp.getStatusCode());
        if (resp.getStatus() == 'OK') {
            string s = resp.getBody();
            system.debug(resp.getBody());
            return s;
        } else {
            system.debug('status is not ok,error:' + resp.getBody());
            return null;
        }
    }

    public static List<Metadata.LayoutSection> GetLayoutSections(string object_name, string layout_name) {
        List<String> componentNameList = new List<String>{ object_name + '-' + layout_name };
        //通过Metadata.Operations.retrieve获取metadata
        //Metadata.Layout -> Metadata.LayoutSection -> Metadata.LayoutColumn objects -> Metadata.LayoutItem objects
        System.debug('componentNameList 171: ' + componentNameList);
        List<Metadata.Metadata> componentList = Metadata.Operations.retrieve(Metadata.MetadataType.Layout, componentNameList);
        System.debug('componentList 173 ' + componentList);
        if (componentList?.size() > 0) {
            Metadata.Layout layout = (Metadata.Layout) componentList.get(0);
            List<Metadata.LayoutSection> layoutSectionList = layout.layoutSections;
            return layoutSectionList;
        } else {
            return null;
        }
    }
}
