exports.up = knex => Promise.resolve()
    .then(() => knex.schema.createTable('countries', (table) => {
        table.string('alpha2', 2)
            .unique()
            .primary();

        table.string('alpha3', 3)
            .unique();

        table.string('name')
            .notNullable();

        table.string('alias');

        table.integer('code', 3);
        table.string('nationality');
        table.integer('priority', 2)
            .defaultTo(0);
    }))
    .then(() => knex.schema.createTable('media', (table) => {
        table.increments('id', 16);

        table.string('path');
        table.string('thumbnail');
        table.integer('index');
        table.string('mime');

        table.string('type');
        table.string('quality', 6);

        table.string('hash');
        table.text('comment');
        table.string('source', 1000);

        table.unique('hash');
        table.unique('source');

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('tags_groups', (table) => {
        table.increments('id', 12);

        table.string('name', 32);
        table.text('description');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('tags', (table) => {
        table.increments('id', 12);
        table.string('name');

        table.text('description');

        table.integer('priority', 2)
            .defaultTo(0);

        table.integer('group_id', 12)
            .references('id')
            .inTable('tags_groups');

        table.integer('alias_for', 12)
            .references('id')
            .inTable('tags');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('tags_posters', (table) => {
        table.integer('tag_id', 12)
            .notNullable()
            .references('id')
            .inTable('tags');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique('tag_id');
    }))
    .then(() => knex.schema.createTable('tags_photos', (table) => {
        table.integer('tag_id', 12)
            .notNullable()
            .references('id')
            .inTable('tags');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique(['tag_id', 'media_id']);
    }))
    .then(() => knex.schema.createTable('networks', (table) => {
        table.increments('id', 12);

        table.string('name');
        table.string('url');
        table.text('description');
        table.json('parameters');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('networks_social', (table) => {
        table.increments('id', 16);

        table.string('url');
        table.string('platform');

        table.integer('network_id', 12)
            .notNullable()
            .references('id')
            .inTable('networks');

        table.unique(['url', 'network_id']);

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('sites', (table) => {
        table.increments('id', 12);

        table.integer('network_id', 12)
            .notNullable()
            .references('id')
            .inTable('networks');

        table.string('name');
        table.string('url');
        table.text('description');
        table.json('parameters');

        table.integer('priority', 3)
            .defaultTo(0);
        table.boolean('show')
            .defaultTo(true);
        table.boolean('scrape')
            .defaultTo(true);

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('sites_tags', (table) => {
        table.integer('tag_id', 12)
            .notNullable()
            .references('id')
            .inTable('tags');

        table.integer('site_id', 12)
            .notNullable()
            .references('id')
            .inTable('sites');

        table.boolean('inherit')
            .defaultTo(false);

        table.unique(['tag_id', 'site_id']);
    }))
    .then(() => knex.schema.createTable('sites_social', (table) => {
        table.increments('id', 16);

        table.string('url');
        table.string('platform');

        table.integer('site_id', 12)
            .notNullable()
            .references('id')
            .inTable('sites');

        table.unique(['url', 'site_id']);

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('studios', (table) => {
        table.increments('id', 12);

        table.integer('network_id', 12)
            .notNullable()
            .references('id')
            .inTable('networks');

        table.string('name');
        table.string('url');
        table.text('description');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('actors', (table) => {
        table.increments('id', 12);

        table.string('name')
            .unique()
            .notNullable();

        table.date('birthdate');
        table.string('gender', 18);
        table.text('description');

        table.string('birth_city');
        table.string('birth_state');
        table.string('birth_country_alpha2', 2)
            .references('alpha2')
            .inTable('countries');

        table.string('residence_city');
        table.string('residence_state');
        table.string('residence_country_alpha2', 2)
            .references('alpha2')
            .inTable('countries');

        table.string('ethnicity');

        table.string('bust', 10);
        table.integer('waist', 3);
        table.integer('hip', 3);
        table.boolean('natural_boobs');

        table.integer('height', 3);
        table.integer('weight', 3);
        table.string('eyes');
        table.string('hair');

        table.boolean('has_tattoos');
        table.boolean('has_piercings');
        table.string('piercings');
        table.string('tattoos');

        table.integer('alias_for', 12)
            .references('id')
            .inTable('actors');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());

        table.datetime('scraped_at');
        table.boolean('scrape_success');
    }))
    .then(() => knex.schema.createTable('actors_avatars', (table) => {
        table.integer('actor_id', 12)
            .notNullable()
            .references('id')
            .inTable('actors');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique('actor_id');
    }))
    .then(() => knex.schema.createTable('actors_photos', (table) => {
        table.integer('actor_id', 12)
            .notNullable()
            .references('id')
            .inTable('actors');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique(['actor_id', 'media_id']);
    }))
    .then(() => knex.schema.createTable('actors_social', (table) => {
        table.increments('id', 16);

        table.string('url');
        table.string('platform');

        table.integer('actor_id', 8)
            .notNullable()
            .references('id')
            .inTable('actors');

        table.unique(['url', 'actor_id']);

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('directors', (table) => {
        table.increments('id', 12);

        table.string('name');
        table.integer('alias_for', 12)
            .references('id')
            .inTable('directors');

        table.string('slug', 32)
            .unique();

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('releases', (table) => {
        table.increments('id', 16);

        table.integer('site_id', 12)
            .notNullable()
            .references('id')
            .inTable('sites');

        table.integer('studio_id', 12)
            .references('id')
            .inTable('studios');

        table.string('type', 10);

        table.string('shoot_id');
        table.string('entry_id');
        table.unique(['site_id', 'entry_id']);

        table.string('url', 1000);
        table.string('title');
        table.string('slug');
        table.date('date');
        table.text('description');

        table.integer('duration')
            .unsigned();

        table.integer('parent_id', 16)
            .references('id')
            .inTable('releases');

        table.boolean('deep');

        table.datetime('created_at')
            .defaultTo(knex.fn.now());
    }))
    .then(() => knex.schema.createTable('releases_actors', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('actor_id', 8)
            .notNullable()
            .references('id')
            .inTable('actors');

        table.unique(['release_id', 'actor_id']);
    }))
    .then(() => knex.schema.createTable('releases_directors', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('director_id', 8)
            .notNullable()
            .references('id')
            .inTable('directors');

        table.unique(['release_id', 'director_id']);
    }))
    .then(() => knex.schema.createTable('releases_posters', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique('release_id');
    }))
    .then(() => knex.schema.createTable('releases_covers', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique(['release_id', 'media_id']);
    }))
    .then(() => knex.schema.createTable('releases_trailers', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique('release_id');
    }))
    .then(() => knex.schema.createTable('releases_teasers', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique('release_id');
    }))
    .then(() => knex.schema.createTable('releases_photos', (table) => {
        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.integer('media_id', 16)
            .notNullable()
            .references('id')
            .inTable('media');

        table.unique(['release_id', 'media_id']);
    }))
    .then(() => knex.schema.createTable('releases_tags', (table) => {
        table.integer('tag_id', 12)
            .notNullable()
            .references('id')
            .inTable('tags');

        table.integer('release_id', 16)
            .notNullable()
            .references('id')
            .inTable('releases');

        table.unique(['tag_id', 'release_id']);
    }))
    .then(() => knex.raw(`
        COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
        COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';

        /*
        CREATE VIEW releases_actors_sortable AS
            SELECT releases_actors.*, actors.gender, actors.name, actors.birthdate FROM releases_actors
            JOIN actors ON releases_actors.actor_id = actors.id;

        CREATE VIEW releases_tags_sortable AS
            SELECT releases_tags.*, tags.name, tags.priority FROM releases_tags
            JOIN tags ON releases_tags.tag_id = tags.id;

        CREATE VIEW actors_releases_sortable AS
            SELECT releases_actors.*, releases.date FROM releases_actors
            JOIN releases ON releases_actors.release_id = releases.id;

        COMMENT ON VIEW releases_actors_sortable IS E'@foreignKey (release_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';
        COMMENT ON VIEW releases_tags_sortable IS E'@foreignKey (release_id) references releases (id)\n@foreignKey (tag_id) references tags (id)';
        COMMENT ON VIEW actors_releases_sortable IS E'@foreignKey (release_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';

        /* allow conversion resolver to be added for height and weight */
        CREATE FUNCTION releases_by_tag_slugs(slugs text[]) RETURNS setof releases AS $$
            SELECT DISTINCT ON (releases.id) releases.* FROM releases
            JOIN releases_tags ON (releases_tags.release_id = releases.id)
            JOIN tags ON (releases_tags.tag_id = tags.id)
            WHERE tags.slug = ANY($1);
        $$ LANGUAGE sql STABLE
        */
    `));

exports.down = knex => knex.raw(`
    DROP FUNCTION IF EXISTS releases_by_tag_slugs;

    DROP VIEW IF EXISTS releases_actors_view;

    DROP TABLE IF EXISTS releases_actors CASCADE;
    DROP TABLE IF EXISTS releases_directors CASCADE;
    DROP TABLE IF EXISTS releases_posters CASCADE;
    DROP TABLE IF EXISTS releases_photos CASCADE;
    DROP TABLE IF EXISTS releases_covers CASCADE;
    DROP TABLE IF EXISTS releases_trailers CASCADE;
    DROP TABLE IF EXISTS releases_teasers CASCADE;
    DROP TABLE IF EXISTS releases_tags CASCADE;
    DROP TABLE IF EXISTS actors_avatars CASCADE;
    DROP TABLE IF EXISTS actors_photos CASCADE;
    DROP TABLE IF EXISTS actors_social CASCADE;
    DROP TABLE IF EXISTS sites_tags CASCADE;
    DROP TABLE IF EXISTS sites_social CASCADE;
    DROP TABLE IF EXISTS networks_social CASCADE;
    DROP TABLE IF EXISTS tags_posters CASCADE;
    DROP TABLE IF EXISTS tags_photos CASCADE;
    DROP TABLE IF EXISTS releases CASCADE;
    DROP TABLE IF EXISTS actors CASCADE;
    DROP TABLE IF EXISTS directors CASCADE;
    DROP TABLE IF EXISTS tags CASCADE;
    DROP TABLE IF EXISTS tags_groups CASCADE;
    DROP TABLE IF EXISTS social CASCADE;
    DROP TABLE IF EXISTS sites CASCADE;
    DROP TABLE IF EXISTS studios CASCADE;
    DROP TABLE IF EXISTS media CASCADE;
    DROP TABLE IF EXISTS countries CASCADE;
    DROP TABLE IF EXISTS networks CASCADE;
`);